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

Commit 1d194046 authored by Vivien Didelot's avatar Vivien Didelot Committed by David S. Miller
Browse files

net: dsa: mv88e6xxx: rework FDB Get Next operation



Add a low level _mv88e6xxx_atu_getnext function for convenient access to
the hardware, and rework the FDB Get Next operation.

This will ease the future integration with VLAN IDs.

Signed-off-by: default avatarVivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent fd231c82
Loading
Loading
Loading
Loading
+59 −21
Original line number Diff line number Diff line
@@ -1314,12 +1314,14 @@ int mv88e6xxx_port_fdb_del(struct dsa_switch *ds, int port,
	return ret;
}

static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port,
				    unsigned char *addr, bool *is_static)
static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
				  const unsigned char *addr,
				  struct mv88e6xxx_atu_entry *entry)
{
	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
	u8 fid = ps->fid[port];
	int ret, state;
	struct mv88e6xxx_atu_entry next = { 0 };
	int ret;

	next.fid = fid;

	ret = _mv88e6xxx_atu_wait(ds);
	if (ret < 0)
@@ -1329,27 +1331,36 @@ static int __mv88e6xxx_port_getnext(struct dsa_switch *ds, int port,
	if (ret < 0)
		return ret;

	do {
	ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
	if (ret < 0)
		return ret;

		ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
	ret = _mv88e6xxx_atu_mac_read(ds, next.mac);
	if (ret < 0)
		return ret;
		state = ret & GLOBAL_ATU_DATA_STATE_MASK;
		if (state == GLOBAL_ATU_DATA_STATE_UNUSED)
			return -ENOENT;
	} while (!(((ret >> 4) & 0xff) & (1 << port)));

	ret = _mv88e6xxx_atu_mac_read(ds, addr);
	ret = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
	if (ret < 0)
		return ret;

	*is_static = state == (is_multicast_ether_addr(addr) ?
			       GLOBAL_ATU_DATA_STATE_MC_STATIC :
			       GLOBAL_ATU_DATA_STATE_UC_STATIC);
	next.state = ret & GLOBAL_ATU_DATA_STATE_MASK;
	if (next.state != GLOBAL_ATU_DATA_STATE_UNUSED) {
		unsigned int mask, shift;

		if (ret & GLOBAL_ATU_DATA_TRUNK) {
			next.trunk = true;
			mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
			shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
		} else {
			next.trunk = false;
			mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
			shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
		}

		next.portv_trunkid = (ret & mask) >> shift;
	}

	*entry = next;
	return 0;
}

@@ -1358,10 +1369,37 @@ int mv88e6xxx_port_fdb_getnext(struct dsa_switch *ds, int port,
			       unsigned char *addr, u16 *vid, bool *is_static)
{
	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
	struct mv88e6xxx_atu_entry next;
	u16 fid;
	int ret;

	mutex_lock(&ps->smi_mutex);
	ret = __mv88e6xxx_port_getnext(ds, port, addr, is_static);

	ret = _mv88e6xxx_port_vid_to_fid(ds, port, *vid);
	if (ret < 0)
		goto unlock;
	fid = ret;

	do {
		if (is_broadcast_ether_addr(addr)) {
			ret = -ENOENT;
			goto unlock;
		}

		ret = _mv88e6xxx_atu_getnext(ds, fid, addr, &next);
		if (ret < 0)
			goto unlock;

		ether_addr_copy(addr, next.mac);

		if (next.state == GLOBAL_ATU_DATA_STATE_UNUSED)
			continue;
	} while (next.trunk || (next.portv_trunkid & BIT(port)) == 0);

	*is_static = next.state == (is_multicast_ether_addr(addr) ?
				    GLOBAL_ATU_DATA_STATE_MC_STATIC :
				    GLOBAL_ATU_DATA_STATE_UC_STATIC);
unlock:
	mutex_unlock(&ps->smi_mutex);

	return ret;