Skip to content

Commit 6c8607e

Browse files
committed
Merge branch 'dsa-add-cross-chip-VLAN-support'
Vivien Didelot says: ==================== net: dsa: add cross-chip VLAN support The current code in DSA does not support cross-chip VLAN. This means that in a multi-chip environment such as this one (similar to ZII Rev B) [CPU].................... (mdio) (eth0) | : : : _|_____ _______ _______ [__sw0__]--[__sw1__]--[__sw2__] | | | | | | | | | v v v v v v v v v p1 p2 p3 p4 p5 p6 p7 p8 p9 adding a VLAN to p9 won't be enough to reach the CPU, until at least one port of sw0 and sw1 join the VLAN as well and become aware of the VID. This patchset makes the DSA core program the VLAN on the CPU and DSA links itself, which brings seamlessly cross-chip VLAN support to DSA. With this series applied*, the hardware VLAN tables of a 3-switch setup look like this after adding a VLAN to only one port of the end switch: # cat /sys/class/net/br0/bridge/default_pvid 42 # cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu # ip link set up master br0 dev lan6 # cat /sys/kernel/debug/mv88e6xxx/sw{0,1,2}/vtu VID FID SID 0 1 2 3 4 5 6 42 1 0 x x x x x = = VID FID SID 0 1 2 3 4 5 6 42 1 0 x x x x x = = VID FID SID 0 1 2 3 4 5 6 7 8 9 42 1 0 u x x x x x x x x = ('x' is excluded, 'u' is untagged, '=' is unmodified DSA and CPU ports.) Completely removing a VLAN entry (which is currently the responsibility of drivers anyway) is not supported yet since it requires some caching. (*) the output is shown from this out-of-tree debugfs patch: https://github.com/vivien/linux/commit/7b61a684b9d6b6a499135a587c7f62a1fddceb8b.patch Changes in v2: - canonical incrementation (port++ instead of ++port) - check CPU and DSA ports before purging a VLAN - add Reviewed-by tags ==================== Signed-off-by: David S. Miller <[email protected]>
2 parents 7eca9cc + adc3a9c commit 6c8607e

File tree

2 files changed

+34
-23
lines changed

2 files changed

+34
-23
lines changed

drivers/net/dsa/mv88e6xxx/chip.c

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1159,11 +1159,10 @@ static int mv88e6xxx_vtu_get(struct mv88e6xxx_chip *chip, u16 vid,
11591159
entry->valid = true;
11601160
entry->vid = vid;
11611161

1162-
/* Include only CPU and DSA ports */
1162+
/* Exclude all ports */
11631163
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i)
1164-
entry->member[i] = dsa_is_normal_port(chip->ds, i) ?
1165-
GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER :
1166-
GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1164+
entry->member[i] =
1165+
GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER;
11671166

11681167
return mv88e6xxx_atu_new(chip, &entry->fid);
11691168
}
@@ -1274,7 +1273,7 @@ mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port,
12741273
}
12751274

12761275
static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
1277-
u16 vid, bool untagged)
1276+
u16 vid, u8 member)
12781277
{
12791278
struct mv88e6xxx_vtu_entry vlan;
12801279
int err;
@@ -1283,9 +1282,7 @@ static int _mv88e6xxx_port_vlan_add(struct mv88e6xxx_chip *chip, int port,
12831282
if (err)
12841283
return err;
12851284

1286-
vlan.member[port] = untagged ?
1287-
GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED :
1288-
GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
1285+
vlan.member[port] = member;
12891286

12901287
return mv88e6xxx_vtu_loadpurge(chip, &vlan);
12911288
}
@@ -1297,15 +1294,23 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
12971294
struct mv88e6xxx_chip *chip = ds->priv;
12981295
bool untagged = vlan->flags & BRIDGE_VLAN_INFO_UNTAGGED;
12991296
bool pvid = vlan->flags & BRIDGE_VLAN_INFO_PVID;
1297+
u8 member;
13001298
u16 vid;
13011299

13021300
if (!chip->info->max_vid)
13031301
return;
13041302

1303+
if (dsa_is_dsa_port(ds, port) || dsa_is_cpu_port(ds, port))
1304+
member = GLOBAL_VTU_DATA_MEMBER_TAG_UNMODIFIED;
1305+
else if (untagged)
1306+
member = GLOBAL_VTU_DATA_MEMBER_TAG_UNTAGGED;
1307+
else
1308+
member = GLOBAL_VTU_DATA_MEMBER_TAG_TAGGED;
1309+
13051310
mutex_lock(&chip->reg_lock);
13061311

13071312
for (vid = vlan->vid_begin; vid <= vlan->vid_end; ++vid)
1308-
if (_mv88e6xxx_port_vlan_add(chip, port, vid, untagged))
1313+
if (_mv88e6xxx_port_vlan_add(chip, port, vid, member))
13091314
netdev_err(ds->ports[port].netdev,
13101315
"failed to add VLAN %d%c\n",
13111316
vid, untagged ? 'u' : 't');
@@ -1320,7 +1325,6 @@ static void mv88e6xxx_port_vlan_add(struct dsa_switch *ds, int port,
13201325
static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
13211326
int port, u16 vid)
13221327
{
1323-
struct dsa_switch *ds = chip->ds;
13241328
struct mv88e6xxx_vtu_entry vlan;
13251329
int i, err;
13261330

@@ -1337,9 +1341,6 @@ static int _mv88e6xxx_port_vlan_del(struct mv88e6xxx_chip *chip,
13371341
/* keep the VLAN unless all ports are excluded */
13381342
vlan.valid = false;
13391343
for (i = 0; i < mv88e6xxx_num_ports(chip); ++i) {
1340-
if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
1341-
continue;
1342-
13431344
if (vlan.member[i] != GLOBAL_VTU_DATA_MEMBER_TAG_NON_MEMBER) {
13441345
vlan.valid = true;
13451346
break;

net/dsa/switch.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -159,19 +159,30 @@ static int dsa_switch_vlan_add(struct dsa_switch *ds,
159159
{
160160
const struct switchdev_obj_port_vlan *vlan = info->vlan;
161161
struct switchdev_trans *trans = info->trans;
162+
DECLARE_BITMAP(members, ds->num_ports);
163+
int port, err;
162164

163-
/* Do not care yet about other switch chips of the fabric */
164-
if (ds->index != info->sw_index)
165-
return 0;
165+
/* Build a mask of VLAN members */
166+
bitmap_zero(members, ds->num_ports);
167+
if (ds->index == info->sw_index)
168+
set_bit(info->port, members);
169+
for (port = 0; port < ds->num_ports; port++)
170+
if (dsa_is_cpu_port(ds, port) || dsa_is_dsa_port(ds, port))
171+
set_bit(port, members);
166172

167173
if (switchdev_trans_ph_prepare(trans)) {
168174
if (!ds->ops->port_vlan_prepare || !ds->ops->port_vlan_add)
169175
return -EOPNOTSUPP;
170176

171-
return ds->ops->port_vlan_prepare(ds, info->port, vlan, trans);
177+
for_each_set_bit(port, members, ds->num_ports) {
178+
err = ds->ops->port_vlan_prepare(ds, port, vlan, trans);
179+
if (err)
180+
return err;
181+
}
172182
}
173183

174-
ds->ops->port_vlan_add(ds, info->port, vlan, trans);
184+
for_each_set_bit(port, members, ds->num_ports)
185+
ds->ops->port_vlan_add(ds, port, vlan, trans);
175186

176187
return 0;
177188
}
@@ -181,14 +192,13 @@ static int dsa_switch_vlan_del(struct dsa_switch *ds,
181192
{
182193
const struct switchdev_obj_port_vlan *vlan = info->vlan;
183194

184-
/* Do not care yet about other switch chips of the fabric */
185-
if (ds->index != info->sw_index)
186-
return 0;
187-
188195
if (!ds->ops->port_vlan_del)
189196
return -EOPNOTSUPP;
190197

191-
return ds->ops->port_vlan_del(ds, info->port, vlan);
198+
if (ds->index == info->sw_index)
199+
return ds->ops->port_vlan_del(ds, info->port, vlan);
200+
201+
return 0;
192202
}
193203

194204
static int dsa_switch_event(struct notifier_block *nb,

0 commit comments

Comments
 (0)