net: dsa: felix: perform MDB migration based on ocelot->multicast list
authorVladimir Oltean <vladimir.oltean@nxp.com>
Thu, 5 May 2022 16:22:12 +0000 (19:22 +0300)
committerJakub Kicinski <kuba@kernel.org>
Sat, 7 May 2022 04:00:12 +0000 (21:00 -0700)
The felix driver is the only user of dsa_port_walk_mdbs(), and there
isn't even a good reason for it, considering that the host MDB entries
are already saved by the ocelot switch lib in the ocelot->multicast list.

Rewrite the multicast entry migration procedure around the
ocelot->multicast list so we can delete dsa_port_walk_mdbs().

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
include/soc/mscc/ocelot.h

index 6443cd5..a4882e4 100644 (file)
@@ -42,27 +42,6 @@ static struct net_device *felix_classify_db(struct dsa_db db)
        }
 }
 
-static int felix_migrate_mdbs_to_npi_port(struct dsa_switch *ds, int port,
-                                         const unsigned char *addr, u16 vid,
-                                         struct dsa_db db)
-{
-       struct net_device *bridge_dev = felix_classify_db(db);
-       struct switchdev_obj_port_mdb mdb;
-       struct ocelot *ocelot = ds->priv;
-       int cpu = ocelot->num_phys_ports;
-       int err;
-
-       memset(&mdb, 0, sizeof(mdb));
-       ether_addr_copy(mdb.addr, addr);
-       mdb.vid = vid;
-
-       err = ocelot_port_mdb_del(ocelot, port, &mdb, bridge_dev);
-       if (err)
-               return err;
-
-       return ocelot_port_mdb_add(ocelot, cpu, &mdb, bridge_dev);
-}
-
 static void felix_migrate_pgid_bit(struct dsa_switch *ds, int from, int to,
                                   int pgid)
 {
@@ -100,28 +79,6 @@ felix_migrate_flood_to_tag_8021q_port(struct dsa_switch *ds, int port)
        felix_migrate_pgid_bit(ds, ocelot->num_phys_ports, port, PGID_BC);
 }
 
-static int
-felix_migrate_mdbs_to_tag_8021q_port(struct dsa_switch *ds, int port,
-                                    const unsigned char *addr, u16 vid,
-                                    struct dsa_db db)
-{
-       struct net_device *bridge_dev = felix_classify_db(db);
-       struct switchdev_obj_port_mdb mdb;
-       struct ocelot *ocelot = ds->priv;
-       int cpu = ocelot->num_phys_ports;
-       int err;
-
-       memset(&mdb, 0, sizeof(mdb));
-       ether_addr_copy(mdb.addr, addr);
-       mdb.vid = vid;
-
-       err = ocelot_port_mdb_del(ocelot, cpu, &mdb, bridge_dev);
-       if (err)
-               return err;
-
-       return ocelot_port_mdb_add(ocelot, port, &mdb, bridge_dev);
-}
-
 /* Set up VCAP ES0 rules for pushing a tag_8021q VLAN towards the CPU such that
  * the tagger can perform RX source port identification.
  */
@@ -450,7 +407,8 @@ static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu)
        if (err)
                return err;
 
-       err = dsa_port_walk_mdbs(ds, cpu, felix_migrate_mdbs_to_tag_8021q_port);
+       err = ocelot_migrate_mdbs(ocelot, BIT(ocelot->num_phys_ports),
+                                 BIT(cpu));
        if (err)
                goto out_tag_8021q_unregister;
 
@@ -473,7 +431,7 @@ static int felix_setup_tag_8021q(struct dsa_switch *ds, int cpu)
 
 out_migrate_flood:
        felix_migrate_flood_to_npi_port(ds, cpu);
-       dsa_port_walk_mdbs(ds, cpu, felix_migrate_mdbs_to_npi_port);
+       ocelot_migrate_mdbs(ocelot, BIT(cpu), BIT(ocelot->num_phys_ports));
 out_tag_8021q_unregister:
        dsa_tag_8021q_unregister(ds);
        return err;
@@ -553,7 +511,8 @@ static int felix_setup_tag_npi(struct dsa_switch *ds, int cpu)
        struct ocelot *ocelot = ds->priv;
        int err;
 
-       err = dsa_port_walk_mdbs(ds, cpu, felix_migrate_mdbs_to_npi_port);
+       err = ocelot_migrate_mdbs(ocelot, BIT(cpu),
+                                 BIT(ocelot->num_phys_ports));
        if (err)
                return err;
 
index 0825a92..9336f3b 100644 (file)
@@ -2610,6 +2610,67 @@ static void ocelot_setup_logical_port_ids(struct ocelot *ocelot)
        }
 }
 
+static int ocelot_migrate_mc(struct ocelot *ocelot, struct ocelot_multicast *mc,
+                            unsigned long from_mask, unsigned long to_mask)
+{
+       unsigned char addr[ETH_ALEN];
+       struct ocelot_pgid *pgid;
+       u16 vid = mc->vid;
+
+       dev_dbg(ocelot->dev,
+               "Migrating multicast %pM vid %d from port mask 0x%lx to 0x%lx\n",
+               mc->addr, mc->vid, from_mask, to_mask);
+
+       /* First clean up the current port mask from hardware, because
+        * we'll be modifying it.
+        */
+       ocelot_pgid_free(ocelot, mc->pgid);
+       ocelot_encode_ports_to_mdb(addr, mc);
+       ocelot_mact_forget(ocelot, addr, vid);
+
+       mc->ports &= ~from_mask;
+       mc->ports |= to_mask;
+
+       pgid = ocelot_mdb_get_pgid(ocelot, mc);
+       if (IS_ERR(pgid)) {
+               dev_err(ocelot->dev,
+                       "Cannot allocate PGID for mdb %pM vid %d\n",
+                       mc->addr, mc->vid);
+               devm_kfree(ocelot->dev, mc);
+               return PTR_ERR(pgid);
+       }
+       mc->pgid = pgid;
+
+       ocelot_encode_ports_to_mdb(addr, mc);
+
+       if (mc->entry_type != ENTRYTYPE_MACv4 &&
+           mc->entry_type != ENTRYTYPE_MACv6)
+               ocelot_write_rix(ocelot, pgid->ports, ANA_PGID_PGID,
+                                pgid->index);
+
+       return ocelot_mact_learn(ocelot, pgid->index, addr, vid,
+                                mc->entry_type);
+}
+
+int ocelot_migrate_mdbs(struct ocelot *ocelot, unsigned long from_mask,
+                       unsigned long to_mask)
+{
+       struct ocelot_multicast *mc;
+       int err;
+
+       list_for_each_entry(mc, &ocelot->multicast, list) {
+               if (!(mc->ports & from_mask))
+                       continue;
+
+               err = ocelot_migrate_mc(ocelot, mc, from_mask, to_mask);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(ocelot_migrate_mdbs);
+
 /* Documentation for PORTID_VAL says:
  *     Logical port number for front port. If port is not a member of a LLAG,
  *     then PORTID must be set to the physical port number.
index 8d8d467..e88bcfe 100644 (file)
@@ -998,6 +998,9 @@ int ocelot_mact_learn_streamdata(struct ocelot *ocelot, int dst_idx,
                                 enum macaccess_entry_type type,
                                 int sfid, int ssid);
 
+int ocelot_migrate_mdbs(struct ocelot *ocelot, unsigned long from_mask,
+                       unsigned long to_mask);
+
 int ocelot_vcap_policer_add(struct ocelot *ocelot, u32 pol_ix,
                            struct ocelot_policer *pol);
 int ocelot_vcap_policer_del(struct ocelot *ocelot, u32 pol_ix);