Commit b7666efe authored by Vivien Didelot's avatar Vivien Didelot Committed by David S. Miller

net: dsa: mv88e6xxx: restore VLANTable map control

The In Chip Port Based VLAN Table contains bits used to restrict which
output ports this input port can send frames to.

With the VLAN filtering enabled, these tables work in conjunction with
the VLAN Table Unit to allow egressing frames.

In order to remove the current dependency to BRIDGE_VLAN_FILTERING for
basic hardware bridging to work, it is necessary to restore a fine
control of each port's VLANTable, on setup and when a port joins or
leaves a bridge.
Signed-off-by: default avatarVivien Didelot <vivien.didelot@savoirfairelinux.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 466dfa07
......@@ -1087,12 +1087,32 @@ static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state)
return ret;
}
static int _mv88e6xxx_port_vlan_map_set(struct dsa_switch *ds, int port,
u16 output_ports)
static int _mv88e6xxx_port_based_vlan_map(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
struct net_device *bridge = ps->ports[port].bridge_dev;
const u16 mask = (1 << ps->num_ports) - 1;
u16 output_ports = 0;
int reg;
int i;
/* allow CPU port or DSA link(s) to send frames to every port */
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
output_ports = mask;
} else {
for (i = 0; i < ps->num_ports; ++i) {
/* allow sending frames to every group member */
if (bridge && ps->ports[i].bridge_dev == bridge)
output_ports |= BIT(i);
/* allow sending frames to CPU port and DSA link(s) */
if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
output_ports |= BIT(i);
}
}
/* prevent frames from going back out of the port they came in on */
output_ports &= ~BIT(port);
reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_BASE_VLAN);
if (reg < 0)
......@@ -2114,7 +2134,17 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
if (err)
goto unlock;
/* Assign the bridge and remap each port's VLANTable */
ps->ports[port].bridge_dev = bridge;
for (i = 0; i < ps->num_ports; ++i) {
if (ps->ports[i].bridge_dev == bridge) {
err = _mv88e6xxx_port_based_vlan_map(ds, i);
if (err)
break;
}
}
unlock:
mutex_unlock(&ps->smi_mutex);
......@@ -2124,8 +2154,9 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
{
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
struct net_device *bridge = ps->ports[port].bridge_dev;
u16 fid;
int err;
int i, err;
mutex_lock(&ps->smi_mutex);
......@@ -2138,7 +2169,17 @@ int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
if (err)
goto unlock;
/* Unassign the bridge and remap each port's VLANTable */
ps->ports[port].bridge_dev = NULL;
for (i = 0; i < ps->num_ports; ++i) {
if (i == port || ps->ports[i].bridge_dev == bridge) {
err = _mv88e6xxx_port_based_vlan_map(ds, i);
if (err)
break;
}
}
unlock:
mutex_unlock(&ps->smi_mutex);
......@@ -2402,15 +2443,14 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
goto abort;
/* Port based VLAN map: give each port its own address
* database, and allow every port to egress frames on all other ports.
* database, and allow bidirectional communication between the
* CPU and DSA port(s), and the other ports.
*/
ret = _mv88e6xxx_port_fid_set(ds, port, port + 1);
if (ret)
goto abort;
reg = BIT(ps->num_ports) - 1; /* all ports */
reg &= ~BIT(port); /* except itself */
ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg);
ret = _mv88e6xxx_port_based_vlan_map(ds, port);
if (ret)
goto abort;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment