In preparation for supporting IGMP snooping with or without the use of
a bridge, add support within b53_common.c to program the ARL entries for
multicast operations. The key difference is that a multicast ARL entry
is comprised of a bitmask of enabled ports, instead of a port number.

Signed-off-by: Florian Fainelli <f.faine...@gmail.com>
---
 drivers/net/dsa/b53/b53_common.c | 62 ++++++++++++++++++++++++++++++--
 drivers/net/dsa/b53/b53_priv.h   |  8 ++++-
 2 files changed, 67 insertions(+), 3 deletions(-)

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 2fef4c564420..6c894ad4768a 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1503,11 +1503,25 @@ static int b53_arl_op(struct b53_device *dev, int op, 
int port,
                idx = 1;
        }
 
-       memset(&ent, 0, sizeof(ent));
-       ent.port = port;
+       /* For multicast address, the port is a bitmask and the validity
+        * is determined by having at least one port being still active
+        */
+       if (!is_multicast_ether_addr(addr)) {
+               ent.port = port;
+               ent.is_valid = is_valid;
+       } else {
+               if (is_valid)
+                       ent.port |= BIT(port);
+               else
+                       ent.port &= ~BIT(port);
+
+               ent.is_valid = !!(ent.port);
+       }
+
        ent.is_valid = is_valid;
        ent.vid = vid;
        ent.is_static = true;
+       ent.is_age = false;
        memcpy(ent.mac, addr, ETH_ALEN);
        b53_arl_from_entry(&mac_vid, &fwd_entry, &ent);
 
@@ -1626,6 +1640,47 @@ int b53_fdb_dump(struct dsa_switch *ds, int port,
 }
 EXPORT_SYMBOL(b53_fdb_dump);
 
+int b53_mdb_prepare(struct dsa_switch *ds, int port,
+                   const struct switchdev_obj_port_mdb *mdb)
+{
+       struct b53_device *priv = ds->priv;
+
+       /* 5325 and 5365 require some more massaging, but could
+        * be supported eventually
+        */
+       if (is5325(priv) || is5365(priv))
+               return -EOPNOTSUPP;
+
+       return 0;
+}
+EXPORT_SYMBOL(b53_mdb_prepare);
+
+void b53_mdb_add(struct dsa_switch *ds, int port,
+                const struct switchdev_obj_port_mdb *mdb)
+{
+       struct b53_device *priv = ds->priv;
+       int ret;
+
+       ret = b53_arl_op(priv, 0, port, mdb->addr, mdb->vid, true);
+       if (ret)
+               dev_err(ds->dev, "failed to add MDB entry\n");
+}
+EXPORT_SYMBOL(b53_mdb_add);
+
+int b53_mdb_del(struct dsa_switch *ds, int port,
+               const struct switchdev_obj_port_mdb *mdb)
+{
+       struct b53_device *priv = ds->priv;
+       int ret;
+
+       ret = b53_arl_op(priv, 0, port, mdb->addr, mdb->vid, false);
+       if (ret)
+               dev_err(ds->dev, "failed to delete MDB entry\n");
+
+       return ret;
+}
+EXPORT_SYMBOL(b53_mdb_del);
+
 int b53_br_join(struct dsa_switch *ds, int port, struct net_device *br)
 {
        struct b53_device *dev = ds->priv;
@@ -1969,6 +2024,9 @@ static const struct dsa_switch_ops b53_switch_ops = {
        .port_fdb_del           = b53_fdb_del,
        .port_mirror_add        = b53_mirror_add,
        .port_mirror_del        = b53_mirror_del,
+       .port_mdb_prepare       = b53_mdb_prepare,
+       .port_mdb_add           = b53_mdb_add,
+       .port_mdb_del           = b53_mdb_del,
 };
 
 struct b53_chip_data {
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index 4dc7ee38b258..620638ff9338 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -251,7 +251,7 @@ b53_build_op(write48, u64);
 b53_build_op(write64, u64);
 
 struct b53_arl_entry {
-       u8 port;
+       u16 port;
        u8 mac[ETH_ALEN];
        u16 vid;
        u8 is_valid:1;
@@ -350,6 +350,12 @@ int b53_fdb_del(struct dsa_switch *ds, int port,
                const unsigned char *addr, u16 vid);
 int b53_fdb_dump(struct dsa_switch *ds, int port,
                 dsa_fdb_dump_cb_t *cb, void *data);
+int b53_mdb_prepare(struct dsa_switch *ds, int port,
+                   const struct switchdev_obj_port_mdb *mdb);
+void b53_mdb_add(struct dsa_switch *ds, int port,
+                const struct switchdev_obj_port_mdb *mdb);
+int b53_mdb_del(struct dsa_switch *ds, int port,
+               const struct switchdev_obj_port_mdb *mdb);
 int b53_mirror_add(struct dsa_switch *ds, int port,
                   struct dsa_mall_mirror_tc_entry *mirror, bool ingress);
 enum dsa_tag_protocol b53_get_tag_protocol(struct dsa_switch *ds, int port);
-- 
2.17.1

Reply via email to