Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 38db25ae authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'Update-DSAs-FDB-API-and-perform-switchdev-cleanup'



Arkadi Sharshevsky says:

====================
Update DSA's FDB API and perform switchdev cleanup

The patchset adds support for configuring static FDB entries via the
switchdev notification chain. The current method for FDB configuration
uses the switchdev's bridge bypass implementation. In order to support
this legacy way and to perform the switchdev cleanup, the implementation
is moved inside DSA.

The DSA drivers cannot sync the software bridge with hardware learned
entries and use the switchdev's implementation of bypass FDB dumping.
Because they are the only ones using this functionality, the fdb_dump
implementation is moved from switchdev code into DSA.

Finally after this changes a major cleanup in switchdev can be done.

Please see individual patches for patch specific change logs.
v1->v2
- Split MDB/vlan dump removal into core/driver removal.

v2->v3
- The self implementation for FDB add/del is moved inside DSA.
====================

Tested-by: default avatarVivien Didelot <vivien.didelot@savoirfairelinux.com>
Tested-by: default avatarFlorian Fainelli <f.fainelli@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 511aeaf4 29ab586c
Loading
Loading
Loading
Loading
+10 −73
Original line number Diff line number Diff line
@@ -1053,49 +1053,6 @@ int b53_vlan_del(struct dsa_switch *ds, int port,
}
EXPORT_SYMBOL(b53_vlan_del);

int b53_vlan_dump(struct dsa_switch *ds, int port,
		  struct switchdev_obj_port_vlan *vlan,
		  switchdev_obj_dump_cb_t *cb)
{
	struct b53_device *dev = ds->priv;
	u16 vid, vid_start = 0, pvid;
	struct b53_vlan *vl;
	int err = 0;

	if (is5325(dev) || is5365(dev))
		vid_start = 1;

	b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &pvid);

	/* Use our software cache for dumps, since we do not have any HW
	 * operation returning only the used/valid VLANs
	 */
	for (vid = vid_start; vid < dev->num_vlans; vid++) {
		vl = &dev->vlans[vid];

		if (!vl->valid)
			continue;

		if (!(vl->members & BIT(port)))
			continue;

		vlan->vid_begin = vlan->vid_end = vid;
		vlan->flags = 0;

		if (vl->untag & BIT(port))
			vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
		if (pvid == vid)
			vlan->flags |= BRIDGE_VLAN_INFO_PVID;

		err = cb(&vlan->obj);
		if (err)
			break;
	}

	return err;
}
EXPORT_SYMBOL(b53_vlan_dump);

/* Address Resolution Logic routines */
static int b53_arl_op_wait(struct b53_device *dev)
{
@@ -1213,9 +1170,8 @@ static int b53_arl_op(struct b53_device *dev, int op, int port,
	return b53_arl_rw_op(dev, 0);
}

int b53_fdb_prepare(struct dsa_switch *ds, int port,
		    const struct switchdev_obj_port_fdb *fdb,
		    struct switchdev_trans *trans)
int b53_fdb_add(struct dsa_switch *ds, int port,
		const unsigned char *addr, u16 vid)
{
	struct b53_device *priv = ds->priv;

@@ -1225,27 +1181,16 @@ int b53_fdb_prepare(struct dsa_switch *ds, int port,
	if (is5325(priv) || is5365(priv))
		return -EOPNOTSUPP;

	return 0;
}
EXPORT_SYMBOL(b53_fdb_prepare);

void b53_fdb_add(struct dsa_switch *ds, int port,
		 const struct switchdev_obj_port_fdb *fdb,
		 struct switchdev_trans *trans)
{
	struct b53_device *priv = ds->priv;

	if (b53_arl_op(priv, 0, port, fdb->addr, fdb->vid, true))
		pr_err("%s: failed to add MAC address\n", __func__);
	return b53_arl_op(priv, 0, port, addr, vid, true);
}
EXPORT_SYMBOL(b53_fdb_add);

int b53_fdb_del(struct dsa_switch *ds, int port,
		const struct switchdev_obj_port_fdb *fdb)
		const unsigned char *addr, u16 vid)
{
	struct b53_device *priv = ds->priv;

	return b53_arl_op(priv, 0, port, fdb->addr, fdb->vid, false);
	return b53_arl_op(priv, 0, port, addr, vid, false);
}
EXPORT_SYMBOL(b53_fdb_del);

@@ -1282,8 +1227,7 @@ static void b53_arl_search_rd(struct b53_device *dev, u8 idx,
}

static int b53_fdb_copy(int port, const struct b53_arl_entry *ent,
			struct switchdev_obj_port_fdb *fdb,
			switchdev_obj_dump_cb_t *cb)
			dsa_fdb_dump_cb_t *cb, void *data)
{
	if (!ent->is_valid)
		return 0;
@@ -1291,16 +1235,11 @@ static int b53_fdb_copy(int port, const struct b53_arl_entry *ent,
	if (port != ent->port)
		return 0;

	ether_addr_copy(fdb->addr, ent->mac);
	fdb->vid = ent->vid;
	fdb->ndm_state = ent->is_static ? NUD_NOARP : NUD_REACHABLE;

	return cb(&fdb->obj);
	return cb(ent->mac, ent->vid, ent->is_static, data);
}

int b53_fdb_dump(struct dsa_switch *ds, int port,
		 struct switchdev_obj_port_fdb *fdb,
		 switchdev_obj_dump_cb_t *cb)
		 dsa_fdb_dump_cb_t *cb, void *data)
{
	struct b53_device *priv = ds->priv;
	struct b53_arl_entry results[2];
@@ -1318,13 +1257,13 @@ int b53_fdb_dump(struct dsa_switch *ds, int port,
			return ret;

		b53_arl_search_rd(priv, 0, &results[0]);
		ret = b53_fdb_copy(port, &results[0], fdb, cb);
		ret = b53_fdb_copy(port, &results[0], cb, data);
		if (ret)
			return ret;

		if (priv->num_arl_entries > 2) {
			b53_arl_search_rd(priv, 1, &results[1]);
			ret = b53_fdb_copy(port, &results[1], fdb, cb);
			ret = b53_fdb_copy(port, &results[1], cb, data);
			if (ret)
				return ret;

@@ -1564,8 +1503,6 @@ static const struct dsa_switch_ops b53_switch_ops = {
	.port_vlan_prepare	= b53_vlan_prepare,
	.port_vlan_add		= b53_vlan_add,
	.port_vlan_del		= b53_vlan_del,
	.port_vlan_dump		= b53_vlan_dump,
	.port_fdb_prepare	= b53_fdb_prepare,
	.port_fdb_dump		= b53_fdb_dump,
	.port_fdb_add		= b53_fdb_add,
	.port_fdb_del		= b53_fdb_del,
+4 −12
Original line number Diff line number Diff line
@@ -393,20 +393,12 @@ void b53_vlan_add(struct dsa_switch *ds, int port,
		  struct switchdev_trans *trans);
int b53_vlan_del(struct dsa_switch *ds, int port,
		 const struct switchdev_obj_port_vlan *vlan);
int b53_vlan_dump(struct dsa_switch *ds, int port,
		  struct switchdev_obj_port_vlan *vlan,
		  switchdev_obj_dump_cb_t *cb);
int b53_fdb_prepare(struct dsa_switch *ds, int port,
		    const struct switchdev_obj_port_fdb *fdb,
		    struct switchdev_trans *trans);
void b53_fdb_add(struct dsa_switch *ds, int port,
		 const struct switchdev_obj_port_fdb *fdb,
		 struct switchdev_trans *trans);
int b53_fdb_add(struct dsa_switch *ds, int port,
		const unsigned char *addr, u16 vid);
int b53_fdb_del(struct dsa_switch *ds, int port,
		const struct switchdev_obj_port_fdb *fdb);
		const unsigned char *addr, u16 vid);
int b53_fdb_dump(struct dsa_switch *ds, int port,
		 struct switchdev_obj_port_fdb *fdb,
		 switchdev_obj_dump_cb_t *cb);
		 dsa_fdb_dump_cb_t *cb, void *data);
int b53_mirror_add(struct dsa_switch *ds, int port,
		   struct dsa_mall_mirror_tc_entry *mirror, bool ingress);
void b53_mirror_del(struct dsa_switch *ds, int port,
+0 −2
Original line number Diff line number Diff line
@@ -1021,8 +1021,6 @@ static const struct dsa_switch_ops bcm_sf2_ops = {
	.port_vlan_prepare	= b53_vlan_prepare,
	.port_vlan_add		= b53_vlan_add,
	.port_vlan_del		= b53_vlan_del,
	.port_vlan_dump		= b53_vlan_dump,
	.port_fdb_prepare	= b53_fdb_prepare,
	.port_fdb_dump		= b53_fdb_dump,
	.port_fdb_add		= b53_fdb_add,
	.port_fdb_del		= b53_fdb_del,
+0 −38
Original line number Diff line number Diff line
@@ -257,43 +257,6 @@ static int dsa_loop_port_vlan_del(struct dsa_switch *ds, int port,
	return 0;
}

static int dsa_loop_port_vlan_dump(struct dsa_switch *ds, int port,
				   struct switchdev_obj_port_vlan *vlan,
				   switchdev_obj_dump_cb_t *cb)
{
	struct dsa_loop_priv *ps = ds->priv;
	struct mii_bus *bus = ps->bus;
	struct dsa_loop_vlan *vl;
	u16 vid, vid_start = 0;
	int err = 0;

	dev_dbg(ds->dev, "%s\n", __func__);

	/* Just do a sleeping operation to make lockdep checks effective */
	mdiobus_read(bus, ps->port_base + port, MII_BMSR);

	for (vid = vid_start; vid < DSA_LOOP_VLANS; vid++) {
		vl = &ps->vlans[vid];

		if (!(vl->members & BIT(port)))
			continue;

		vlan->vid_begin = vlan->vid_end = vid;
		vlan->flags = 0;

		if (vl->untagged & BIT(port))
			vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
		if (ps->pvid == vid)
			vlan->flags |= BRIDGE_VLAN_INFO_PVID;

		err = cb(&vlan->obj);
		if (err)
			break;
	}

	return err;
}

static struct dsa_switch_ops dsa_loop_driver = {
	.get_tag_protocol	= dsa_loop_get_protocol,
	.setup			= dsa_loop_setup,
@@ -310,7 +273,6 @@ static struct dsa_switch_ops dsa_loop_driver = {
	.port_vlan_prepare	= dsa_loop_port_vlan_prepare,
	.port_vlan_add		= dsa_loop_port_vlan_add,
	.port_vlan_del		= dsa_loop_port_vlan_del,
	.port_vlan_dump		= dsa_loop_port_vlan_dump,
};

static int dsa_loop_drv_probe(struct mdio_device *mdiodev)
+30 −94
Original line number Diff line number Diff line
@@ -638,55 +638,6 @@ static int ksz_port_vlan_del(struct dsa_switch *ds, int port,
	return 0;
}

static int ksz_port_vlan_dump(struct dsa_switch *ds, int port,
			      struct switchdev_obj_port_vlan *vlan,
			      switchdev_obj_dump_cb_t *cb)
{
	struct ksz_device *dev = ds->priv;
	u16 vid;
	u16 data;
	struct vlan_table *vlan_cache;
	int err = 0;

	mutex_lock(&dev->vlan_mutex);

	/* use dev->vlan_cache due to lack of searching valid vlan entry */
	for (vid = vlan->vid_begin; vid < dev->num_vlans; vid++) {
		vlan_cache = &dev->vlan_cache[vid];

		if (!(vlan_cache->table[0] & VLAN_VALID))
			continue;

		vlan->vid_begin = vid;
		vlan->vid_end = vid;
		vlan->flags = 0;
		if (vlan_cache->table[2] & BIT(port)) {
			if (vlan_cache->table[1] & BIT(port))
				vlan->flags |= BRIDGE_VLAN_INFO_UNTAGGED;
			ksz_pread16(dev, port, REG_PORT_DEFAULT_VID, &data);
			if (vid == (data & 0xFFFFF))
				vlan->flags |= BRIDGE_VLAN_INFO_PVID;

			err = cb(&vlan->obj);
			if (err)
				break;
		}
	}

	mutex_unlock(&dev->vlan_mutex);

	return err;
}

static int ksz_port_fdb_prepare(struct dsa_switch *ds, int port,
				const struct switchdev_obj_port_fdb *fdb,
				struct switchdev_trans *trans)
{
	/* nothing needed */

	return 0;
}

struct alu_struct {
	/* entry 1 */
	u8	is_static:1;
@@ -706,30 +657,31 @@ struct alu_struct {
	u8	mac[ETH_ALEN];
};

static void ksz_port_fdb_add(struct dsa_switch *ds, int port,
			     const struct switchdev_obj_port_fdb *fdb,
			     struct switchdev_trans *trans)
static int ksz_port_fdb_add(struct dsa_switch *ds, int port,
			    const unsigned char *addr, u16 vid)
{
	struct ksz_device *dev = ds->priv;
	u32 alu_table[4];
	u32 data;
	int ret = 0;

	mutex_lock(&dev->alu_mutex);

	/* find any entry with mac & vid */
	data = fdb->vid << ALU_FID_INDEX_S;
	data |= ((fdb->addr[0] << 8) | fdb->addr[1]);
	data = vid << ALU_FID_INDEX_S;
	data |= ((addr[0] << 8) | addr[1]);
	ksz_write32(dev, REG_SW_ALU_INDEX_0, data);

	data = ((fdb->addr[2] << 24) | (fdb->addr[3] << 16));
	data |= ((fdb->addr[4] << 8) | fdb->addr[5]);
	data = ((addr[2] << 24) | (addr[3] << 16));
	data |= ((addr[4] << 8) | addr[5]);
	ksz_write32(dev, REG_SW_ALU_INDEX_1, data);

	/* start read operation */
	ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_READ | ALU_START);

	/* wait to be finished */
	if (wait_alu_ready(dev, ALU_START, 1000) < 0) {
	ret = wait_alu_ready(dev, ALU_START, 1000);
	if (ret < 0) {
		dev_dbg(dev->dev, "Failed to read ALU\n");
		goto exit;
	}
@@ -740,27 +692,30 @@ static void ksz_port_fdb_add(struct dsa_switch *ds, int port,
	/* update ALU entry */
	alu_table[0] = ALU_V_STATIC_VALID;
	alu_table[1] |= BIT(port);
	if (fdb->vid)
	if (vid)
		alu_table[1] |= ALU_V_USE_FID;
	alu_table[2] = (fdb->vid << ALU_V_FID_S);
	alu_table[2] |= ((fdb->addr[0] << 8) | fdb->addr[1]);
	alu_table[3] = ((fdb->addr[2] << 24) | (fdb->addr[3] << 16));
	alu_table[3] |= ((fdb->addr[4] << 8) | fdb->addr[5]);
	alu_table[2] = (vid << ALU_V_FID_S);
	alu_table[2] |= ((addr[0] << 8) | addr[1]);
	alu_table[3] = ((addr[2] << 24) | (addr[3] << 16));
	alu_table[3] |= ((addr[4] << 8) | addr[5]);

	write_table(ds, alu_table);

	ksz_write32(dev, REG_SW_ALU_CTRL__4, ALU_WRITE | ALU_START);

	/* wait to be finished */
	if (wait_alu_ready(dev, ALU_START, 1000) < 0)
		dev_dbg(dev->dev, "Failed to read ALU\n");
	ret = wait_alu_ready(dev, ALU_START, 1000);
	if (ret < 0)
		dev_dbg(dev->dev, "Failed to write ALU\n");

exit:
	mutex_unlock(&dev->alu_mutex);

	return ret;
}

static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
			    const struct switchdev_obj_port_fdb *fdb)
			    const unsigned char *addr, u16 vid)
{
	struct ksz_device *dev = ds->priv;
	u32 alu_table[4];
@@ -770,12 +725,12 @@ static int ksz_port_fdb_del(struct dsa_switch *ds, int port,
	mutex_lock(&dev->alu_mutex);

	/* read any entry with mac & vid */
	data = fdb->vid << ALU_FID_INDEX_S;
	data |= ((fdb->addr[0] << 8) | fdb->addr[1]);
	data = vid << ALU_FID_INDEX_S;
	data |= ((addr[0] << 8) | addr[1]);
	ksz_write32(dev, REG_SW_ALU_INDEX_0, data);

	data = ((fdb->addr[2] << 24) | (fdb->addr[3] << 16));
	data |= ((fdb->addr[4] << 8) | fdb->addr[5]);
	data = ((addr[2] << 24) | (addr[3] << 16));
	data |= ((addr[4] << 8) | addr[5]);
	ksz_write32(dev, REG_SW_ALU_INDEX_1, data);

	/* start read operation */
@@ -850,12 +805,11 @@ static void convert_alu(struct alu_struct *alu, u32 *alu_table)
}

static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
			     struct switchdev_obj_port_fdb *fdb,
			     switchdev_obj_dump_cb_t *cb)
			     dsa_fdb_dump_cb_t *cb, void *data)
{
	struct ksz_device *dev = ds->priv;
	int ret = 0;
	u32 data;
	u32 ksz_data;
	u32 alu_table[4];
	struct alu_struct alu;
	int timeout;
@@ -868,8 +822,8 @@ static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
	do {
		timeout = 1000;
		do {
			ksz_read32(dev, REG_SW_ALU_CTRL__4, &data);
			if ((data & ALU_VALID) || !(data & ALU_START))
			ksz_read32(dev, REG_SW_ALU_CTRL__4, &ksz_data);
			if ((ksz_data & ALU_VALID) || !(ksz_data & ALU_START))
				break;
			usleep_range(1, 10);
		} while (timeout-- > 0);
@@ -886,18 +840,11 @@ static int ksz_port_fdb_dump(struct dsa_switch *ds, int port,
		convert_alu(&alu, alu_table);

		if (alu.port_forward & BIT(port)) {
			fdb->vid = alu.fid;
			if (alu.is_static)
				fdb->ndm_state = NUD_NOARP;
			else
				fdb->ndm_state = NUD_REACHABLE;
			ether_addr_copy(fdb->addr, alu.mac);

			ret = cb(&fdb->obj);
			ret = cb(alu.mac, alu.fid, alu.is_static, data);
			if (ret)
				goto exit;
		}
	} while (data & ALU_START);
	} while (ksz_data & ALU_START);

exit:

@@ -1065,14 +1012,6 @@ static int ksz_port_mdb_del(struct dsa_switch *ds, int port,
	return ret;
}

static int ksz_port_mdb_dump(struct dsa_switch *ds, int port,
			     struct switchdev_obj_port_mdb *mdb,
			     switchdev_obj_dump_cb_t *cb)
{
	/* this is not called by switch layer */
	return 0;
}

static int ksz_port_mirror_add(struct dsa_switch *ds, int port,
			       struct dsa_mall_mirror_tc_entry *mirror,
			       bool ingress)
@@ -1129,15 +1068,12 @@ static const struct dsa_switch_ops ksz_switch_ops = {
	.port_vlan_prepare	= ksz_port_vlan_prepare,
	.port_vlan_add		= ksz_port_vlan_add,
	.port_vlan_del		= ksz_port_vlan_del,
	.port_vlan_dump		= ksz_port_vlan_dump,
	.port_fdb_prepare	= ksz_port_fdb_prepare,
	.port_fdb_dump		= ksz_port_fdb_dump,
	.port_fdb_add		= ksz_port_fdb_add,
	.port_fdb_del		= ksz_port_fdb_del,
	.port_mdb_prepare       = ksz_port_mdb_prepare,
	.port_mdb_add           = ksz_port_mdb_add,
	.port_mdb_del           = ksz_port_mdb_del,
	.port_mdb_dump          = ksz_port_mdb_dump,
	.port_mirror_add	= ksz_port_mirror_add,
	.port_mirror_del	= ksz_port_mirror_del,
};
Loading