Skip to content

Commit b7666ef

Browse files
viviendavem330
authored andcommitted
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: Vivien Didelot <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 466dfa0 commit b7666ef

File tree

1 file changed

+47
-7
lines changed

1 file changed

+47
-7
lines changed

drivers/net/dsa/mv88e6xxx.c

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,12 +1087,32 @@ static int mv88e6xxx_set_port_state(struct dsa_switch *ds, int port, u8 state)
10871087
return ret;
10881088
}
10891089

1090-
static int _mv88e6xxx_port_vlan_map_set(struct dsa_switch *ds, int port,
1091-
u16 output_ports)
1090+
static int _mv88e6xxx_port_based_vlan_map(struct dsa_switch *ds, int port)
10921091
{
10931092
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
1093+
struct net_device *bridge = ps->ports[port].bridge_dev;
10941094
const u16 mask = (1 << ps->num_ports) - 1;
1095+
u16 output_ports = 0;
10951096
int reg;
1097+
int i;
1098+
1099+
/* allow CPU port or DSA link(s) to send frames to every port */
1100+
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port)) {
1101+
output_ports = mask;
1102+
} else {
1103+
for (i = 0; i < ps->num_ports; ++i) {
1104+
/* allow sending frames to every group member */
1105+
if (bridge && ps->ports[i].bridge_dev == bridge)
1106+
output_ports |= BIT(i);
1107+
1108+
/* allow sending frames to CPU port and DSA link(s) */
1109+
if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
1110+
output_ports |= BIT(i);
1111+
}
1112+
}
1113+
1114+
/* prevent frames from going back out of the port they came in on */
1115+
output_ports &= ~BIT(port);
10961116

10971117
reg = _mv88e6xxx_reg_read(ds, REG_PORT(port), PORT_BASE_VLAN);
10981118
if (reg < 0)
@@ -2114,7 +2134,17 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
21142134
if (err)
21152135
goto unlock;
21162136

2137+
/* Assign the bridge and remap each port's VLANTable */
21172138
ps->ports[port].bridge_dev = bridge;
2139+
2140+
for (i = 0; i < ps->num_ports; ++i) {
2141+
if (ps->ports[i].bridge_dev == bridge) {
2142+
err = _mv88e6xxx_port_based_vlan_map(ds, i);
2143+
if (err)
2144+
break;
2145+
}
2146+
}
2147+
21182148
unlock:
21192149
mutex_unlock(&ps->smi_mutex);
21202150

@@ -2124,8 +2154,9 @@ int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port,
21242154
int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
21252155
{
21262156
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
2157+
struct net_device *bridge = ps->ports[port].bridge_dev;
21272158
u16 fid;
2128-
int err;
2159+
int i, err;
21292160

21302161
mutex_lock(&ps->smi_mutex);
21312162

@@ -2138,7 +2169,17 @@ int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port)
21382169
if (err)
21392170
goto unlock;
21402171

2172+
/* Unassign the bridge and remap each port's VLANTable */
21412173
ps->ports[port].bridge_dev = NULL;
2174+
2175+
for (i = 0; i < ps->num_ports; ++i) {
2176+
if (i == port || ps->ports[i].bridge_dev == bridge) {
2177+
err = _mv88e6xxx_port_based_vlan_map(ds, i);
2178+
if (err)
2179+
break;
2180+
}
2181+
}
2182+
21422183
unlock:
21432184
mutex_unlock(&ps->smi_mutex);
21442185

@@ -2402,15 +2443,14 @@ static int mv88e6xxx_setup_port(struct dsa_switch *ds, int port)
24022443
goto abort;
24032444

24042445
/* Port based VLAN map: give each port its own address
2405-
* database, and allow every port to egress frames on all other ports.
2446+
* database, and allow bidirectional communication between the
2447+
* CPU and DSA port(s), and the other ports.
24062448
*/
24072449
ret = _mv88e6xxx_port_fid_set(ds, port, port + 1);
24082450
if (ret)
24092451
goto abort;
24102452

2411-
reg = BIT(ps->num_ports) - 1; /* all ports */
2412-
reg &= ~BIT(port); /* except itself */
2413-
ret = _mv88e6xxx_port_vlan_map_set(ds, port, reg);
2453+
ret = _mv88e6xxx_port_based_vlan_map(ds, port);
24142454
if (ret)
24152455
goto abort;
24162456

0 commit comments

Comments
 (0)