Commit 28de0f9f authored by Vladimir Oltean's avatar Vladimir Oltean Committed by Jakub Kicinski
Browse files

net: dsa: felix: perform MDB migration based on ocelot->multicast list



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: default avatarVladimir Oltean <vladimir.oltean@nxp.com>
Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parent a51c1c3f
Loading
Loading
Loading
Loading
+5 −46
Original line number Diff line number Diff line
@@ -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;

+61 −0
Original line number Diff line number Diff line
@@ -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.
+3 −0
Original line number Diff line number Diff line
@@ -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);