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

Commit 6e75f3c3 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dsa-mv88e6xxx-ATU'



Vivien Didelot says:

====================
net: dsa: mv88e6xxx: improve ATU move operations

This patchset completes the set of available Address Translation Unit
operations.

These Marvell switches have 4 operations to flush or (re)move, all or
only non-static MAC addresses, from the entire set of databases or from
just a particular one.

The first 3 patches introduce a generic _mv88e6xxx_atu_flush_move
function. The 4 remaining patches update a few FID operations in the
driver on setup, when a port join or leave a VLAN, or change state.

This is a step forward improving the hardware bridging support in DSA
and 88E6352-compatible switches.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c36ba660 2b8157b1
Loading
Loading
Loading
Loading
+118 −33
Original line number Diff line number Diff line
@@ -1036,14 +1036,10 @@ int mv88e6xxx_set_eee(struct dsa_switch *ds, int port,
	return ret;
}

static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd)
static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, u16 cmd)
{
	int ret;

	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid);
	if (ret < 0)
		return ret;

	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_OP, cmd);
	if (ret < 0)
		return ret;
@@ -1051,15 +1047,98 @@ static int _mv88e6xxx_atu_cmd(struct dsa_switch *ds, int fid, u16 cmd)
	return _mv88e6xxx_atu_wait(ds);
}

static int _mv88e6xxx_atu_data_write(struct dsa_switch *ds,
				     struct mv88e6xxx_atu_entry *entry)
{
	u16 data = entry->state & GLOBAL_ATU_DATA_STATE_MASK;

	if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
		unsigned int mask, shift;

		if (entry->trunk) {
			data |= GLOBAL_ATU_DATA_TRUNK;
			mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
			shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
		} else {
			mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
			shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
		}

		data |= (entry->portv_trunkid << shift) & mask;
	}

	return _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, data);
}

static int _mv88e6xxx_atu_flush_move(struct dsa_switch *ds,
				     struct mv88e6xxx_atu_entry *entry,
				     bool static_too)
{
	int op;
	int err;

	err = _mv88e6xxx_atu_wait(ds);
	if (err)
		return err;

	err = _mv88e6xxx_atu_data_write(ds, entry);
	if (err)
		return err;

	if (entry->fid) {
		err = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID,
					   entry->fid);
		if (err)
			return err;

		op = static_too ? GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB :
			GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB;
	} else {
		op = static_too ? GLOBAL_ATU_OP_FLUSH_MOVE_ALL :
			GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC;
	}

	return _mv88e6xxx_atu_cmd(ds, op);
}

static int _mv88e6xxx_atu_flush(struct dsa_switch *ds, u16 fid, bool static_too)
{
	struct mv88e6xxx_atu_entry entry = {
		.fid = fid,
		.state = 0, /* EntryState bits must be 0 */
	};

	return _mv88e6xxx_atu_flush_move(ds, &entry, static_too);
}

static int _mv88e6xxx_flush_fid(struct dsa_switch *ds, int fid)
{
	int ret;
	return _mv88e6xxx_atu_flush(ds, fid, false);
}

	ret = _mv88e6xxx_atu_wait(ds);
	if (ret < 0)
		return ret;
static int _mv88e6xxx_atu_move(struct dsa_switch *ds, u16 fid, int from_port,
			       int to_port, bool static_too)
{
	struct mv88e6xxx_atu_entry entry = {
		.trunk = false,
		.fid = fid,
	};

	/* EntryState bits must be 0xF */
	entry.state = GLOBAL_ATU_DATA_STATE_MASK;

	/* ToPort and FromPort are respectively in PortVec bits 7:4 and 3:0 */
	entry.portv_trunkid = (to_port & 0x0f) << 4;
	entry.portv_trunkid |= from_port & 0x0f;

	return _mv88e6xxx_atu_flush_move(ds, &entry, static_too);
}

	return _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB);
static int _mv88e6xxx_atu_remove(struct dsa_switch *ds, u16 fid, int port,
				 bool static_too)
{
	/* Destination port 0xF means remove the entries */
	return _mv88e6xxx_atu_move(ds, fid, port, 0x0f, static_too);
}

static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state)
@@ -1084,7 +1163,7 @@ static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state)
		 */
		if (oldstate >= PORT_CONTROL_STATE_LEARNING &&
		    state <= PORT_CONTROL_STATE_BLOCKING) {
			ret = _mv88e6xxx_flush_fid(ds, ps->fid[port]);
			ret = _mv88e6xxx_atu_remove(ds, 0, port, false);
			if (ret)
				goto abort;
		}
@@ -1576,7 +1655,8 @@ static int _mv88e6xxx_vlan_init(struct dsa_switch *ds, u16 vid,
			return -ENOSPC;
		}

		err = _mv88e6xxx_flush_fid(ds, vlan.fid);
		/* Clear all MAC addresses from the new database */
		err = _mv88e6xxx_atu_flush(ds, vlan.fid, true);
		if (err)
			return err;

@@ -1653,6 +1733,10 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port, u16 vid)
	if (err)
		goto unlock;

	err = _mv88e6xxx_atu_remove(ds, vlan.fid, port, false);
	if (err)
		goto unlock;

	if (!keep)
		clear_bit(vlan.fid, ps->fid_bitmap);

@@ -1761,7 +1845,6 @@ static int _mv88e6xxx_atu_mac_read(struct dsa_switch *ds, unsigned char *addr)
static int _mv88e6xxx_atu_load(struct dsa_switch *ds,
			       struct mv88e6xxx_atu_entry *entry)
{
	u16 reg = 0;
	int ret;

	ret = _mv88e6xxx_atu_wait(ds);
@@ -1772,28 +1855,15 @@ static int _mv88e6xxx_atu_load(struct dsa_switch *ds,
	if (ret < 0)
		return ret;

	if (entry->state != GLOBAL_ATU_DATA_STATE_UNUSED) {
		unsigned int mask, shift;

		if (entry->trunk) {
			reg |= GLOBAL_ATU_DATA_TRUNK;
			mask = GLOBAL_ATU_DATA_TRUNK_ID_MASK;
			shift = GLOBAL_ATU_DATA_TRUNK_ID_SHIFT;
		} else {
			mask = GLOBAL_ATU_DATA_PORT_VECTOR_MASK;
			shift = GLOBAL_ATU_DATA_PORT_VECTOR_SHIFT;
		}

		reg |= (entry->portv_trunkid << shift) & mask;
	}

	reg |= entry->state & GLOBAL_ATU_DATA_STATE_MASK;
	ret = _mv88e6xxx_atu_data_write(ds, entry);
	if (ret < 0)
		return ret;

	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_DATA, reg);
	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, entry->fid);
	if (ret < 0)
		return ret;

	return _mv88e6xxx_atu_cmd(ds, entry->fid, GLOBAL_ATU_OP_LOAD_DB);
	return _mv88e6xxx_atu_cmd(ds, GLOBAL_ATU_OP_LOAD_DB);
}

static int _mv88e6xxx_port_vid_to_fid(struct dsa_switch *ds, int port, u16 vid)
@@ -1884,7 +1954,11 @@ static int _mv88e6xxx_atu_getnext(struct dsa_switch *ds, u16 fid,
	if (ret < 0)
		return ret;

	ret = _mv88e6xxx_atu_cmd(ds, fid, GLOBAL_ATU_OP_GET_NEXT_DB);
	ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID, fid);
	if (ret < 0)
		return ret;

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

@@ -2308,9 +2382,15 @@ static int mv88e6xxx_atu_show_db(struct seq_file *s, struct dsa_switch *ds,
		return ret;

	do {
		ret = _mv88e6xxx_atu_cmd(ds, dbnum, GLOBAL_ATU_OP_GET_NEXT_DB);
		ret = _mv88e6xxx_reg_write(ds, REG_GLOBAL, GLOBAL_ATU_FID,
					   dbnum);
		if (ret < 0)
			return ret;

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

		data = _mv88e6xxx_reg_read(ds, REG_GLOBAL, GLOBAL_ATU_DATA);
		if (data < 0)
			return data;
@@ -2635,6 +2715,11 @@ int mv88e6xxx_setup_global(struct dsa_switch *ds)
	if (ret < 0)
		goto unlock;

	/* Clear all ATU entries */
	ret = _mv88e6xxx_atu_flush(ds, 0, true);
	if (ret < 0)
		goto unlock;

	/* Clear all the VTU and STU entries */
	ret = _mv88e6xxx_vtu_stu_flush(ds);
unlock:
+4 −4
Original line number Diff line number Diff line
@@ -226,12 +226,12 @@
#define GLOBAL_ATU_OP		0x0b
#define GLOBAL_ATU_OP_BUSY	BIT(15)
#define GLOBAL_ATU_OP_NOP		(0 << 12)
#define GLOBAL_ATU_OP_FLUSH_ALL		((1 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_FLUSH_NON_STATIC	((2 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL		((1 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC	((2 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_LOAD_DB		((3 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_GET_NEXT_DB	((4 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_FLUSH_DB		((5 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_FLUSH_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_FLUSH_MOVE_ALL_DB		((5 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_FLUSH_MOVE_NON_STATIC_DB ((6 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_OP_GET_CLR_VIOLATION	  ((7 << 12) | GLOBAL_ATU_OP_BUSY)
#define GLOBAL_ATU_DATA		0x0c
#define GLOBAL_ATU_DATA_TRUNK			BIT(15)