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

Commit 207afda1 authored by Vivien Didelot's avatar Vivien Didelot Committed by David S. Miller
Browse files

net: dsa: mv88e6xxx: share the same default FDB



For hardware cross-chip bridging to work, user ports *and* DSA ports
need to share a common address database, in order to switch a frame to
the correct interconnected device.

This is currently working for VLAN filtering aware systems, since Linux
will implement a bridge group as a 802.1Q VLAN, which has its own FDB,
including DSA and CPU links as members.

However when the system doesn't support VLAN filtering, Linux only
relies on the port-based VLAN to implement a bridge group.

To fix hardware cross-chip bridging for such systems, set the same
default address database 0 for user and DSA ports, instead of giving
them all a different default database.

Note that the bridging code prevents frames to egress between unbridged
ports, and flushes FDB entries of a port when changing its STP state.

Also note that the FID 0 is special and means "all" for ATU operations,
but it's OK since it is used as a default forwarding address database.

Fixes: 2db9ce1f ("net: dsa: mv88e6xxx: assign default FDB to ports")
Fixes: 466dfa07 ("net: dsa: mv88e6xxx: assign dynamic FDB to bridges")
Signed-off-by: default avatarVivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 996ecb82
Loading
Loading
Loading
Loading
+2 −26
Original line number Original line Diff line number Diff line
@@ -2181,27 +2181,10 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
			       struct net_device *bridge)
			       struct net_device *bridge)
{
{
	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
	u16 fid;
	int i, err;
	int i, err;


	mutex_lock(&ps->smi_mutex);
	mutex_lock(&ps->smi_mutex);


	/* Get or create the bridge FID and assign it to the port */
	for (i = 0; i < ps->num_ports; ++i)
		if (ps->ports[i].bridge_dev == bridge)
			break;

	if (i < ps->num_ports)
		err = _mv88e6xxx_port_fid_get(ds, i, &fid);
	else
		err = _mv88e6xxx_fid_new(ds, &fid);
	if (err)
		goto unlock;

	err = _mv88e6xxx_port_fid_set(ds, port, fid);
	if (err)
		goto unlock;

	/* Assign the bridge and remap each port's VLANTable */
	/* Assign the bridge and remap each port's VLANTable */
	ps->ports[port].bridge_dev = bridge;
	ps->ports[port].bridge_dev = bridge;


@@ -2213,7 +2196,6 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
		}
		}
	}
	}


unlock:
	mutex_unlock(&ps->smi_mutex);
	mutex_unlock(&ps->smi_mutex);


	return err;
	return err;
@@ -2223,16 +2205,10 @@ void mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
{
{
	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
	struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
	struct net_device *bridge = ps->ports[port].bridge_dev;
	struct net_device *bridge = ps->ports[port].bridge_dev;
	u16 fid;
	int i;
	int i;


	mutex_lock(&ps->smi_mutex);
	mutex_lock(&ps->smi_mutex);


	/* Give the port a fresh Filtering Information Database */
	if (_mv88e6xxx_fid_new(ds, &fid) ||
	    _mv88e6xxx_port_fid_set(ds, port, fid))
		netdev_warn(ds->ports[port], "failed to assign a new FID\n");

	/* Unassign the bridge and remap each port's VLANTable */
	/* Unassign the bridge and remap each port's VLANTable */
	ps->ports[port].bridge_dev = NULL;
	ps->ports[port].bridge_dev = NULL;


@@ -2558,11 +2534,11 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
	if (ret)
	if (ret)
		goto abort;
		goto abort;


	/* Port based VLAN map: give each port its own address
	/* Port based VLAN map: give each port the same default address
	 * database, and allow bidirectional communication between the
	 * database, and allow bidirectional communication between the
	 * CPU and DSA port(s), and the other ports.
	 * CPU and DSA port(s), and the other ports.
	 */
	 */
	ret = _mv88e6xxx_port_fid_set(ds, port, port + 1);
	ret = _mv88e6xxx_port_fid_set(ds, port, 0);
	if (ret)
	if (ret)
		goto abort;
		goto abort;