Skip to content

Commit dad8d7c

Browse files
ffainellidavem330
authored andcommitted
net: dsa: b53: Properly account for VLAN filtering
VLAN filtering can be built into the kernel, and also dynamically turned on/off through the bridge master device. Allow re-configuring the switch appropriately to account for that by deciding whether VLAN table (v_table) misses should lead to a drop or forward. Fixes: a2482d2 ("net: dsa: b53: Plug in VLAN support") Signed-off-by: Florian Fainelli <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent fea8335 commit dad8d7c

File tree

2 files changed

+57
-5
lines changed

2 files changed

+57
-5
lines changed

drivers/net/dsa/b53/b53_common.c

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -344,7 +344,8 @@ static void b53_set_forwarding(struct b53_device *dev, int enable)
344344
b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
345345
}
346346

347-
static void b53_enable_vlan(struct b53_device *dev, bool enable)
347+
static void b53_enable_vlan(struct b53_device *dev, bool enable,
348+
bool enable_filtering)
348349
{
349350
u8 mgmt, vc0, vc1, vc4 = 0, vc5;
350351

@@ -369,8 +370,13 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable)
369370
vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
370371
vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN;
371372
vc4 &= ~VC4_ING_VID_CHECK_MASK;
372-
vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
373-
vc5 |= VC5_DROP_VTABLE_MISS;
373+
if (enable_filtering) {
374+
vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
375+
vc5 |= VC5_DROP_VTABLE_MISS;
376+
} else {
377+
vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S;
378+
vc5 &= ~VC5_DROP_VTABLE_MISS;
379+
}
374380

375381
if (is5325(dev))
376382
vc0 &= ~VC0_RESERVED_1;
@@ -420,6 +426,9 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable)
420426
}
421427

422428
b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
429+
430+
dev->vlan_enabled = enable;
431+
dev->vlan_filtering_enabled = enable_filtering;
423432
}
424433

425434
static int b53_set_jumbo(struct b53_device *dev, bool enable, bool allow_10_100)
@@ -656,7 +665,7 @@ int b53_configure_vlan(struct dsa_switch *ds)
656665
b53_do_vlan_op(dev, VTA_CMD_CLEAR);
657666
}
658667

659-
b53_enable_vlan(dev, false);
668+
b53_enable_vlan(dev, false, dev->vlan_filtering_enabled);
660669

661670
b53_for_each_port(dev, i)
662671
b53_write16(dev, B53_VLAN_PAGE,
@@ -1265,6 +1274,46 @@ EXPORT_SYMBOL(b53_phylink_mac_link_up);
12651274

12661275
int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
12671276
{
1277+
struct b53_device *dev = ds->priv;
1278+
struct net_device *bridge_dev;
1279+
unsigned int i;
1280+
u16 pvid, new_pvid;
1281+
1282+
/* Handle the case were multiple bridges span the same switch device
1283+
* and one of them has a different setting than what is being requested
1284+
* which would be breaking filtering semantics for any of the other
1285+
* bridge devices.
1286+
*/
1287+
b53_for_each_port(dev, i) {
1288+
bridge_dev = dsa_to_port(ds, i)->bridge_dev;
1289+
if (bridge_dev &&
1290+
bridge_dev != dsa_to_port(ds, port)->bridge_dev &&
1291+
br_vlan_enabled(bridge_dev) != vlan_filtering) {
1292+
netdev_err(bridge_dev,
1293+
"VLAN filtering is global to the switch!\n");
1294+
return -EINVAL;
1295+
}
1296+
}
1297+
1298+
b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &pvid);
1299+
new_pvid = pvid;
1300+
if (dev->vlan_filtering_enabled && !vlan_filtering) {
1301+
/* Filtering is currently enabled, use the default PVID since
1302+
* the bridge does not expect tagging anymore
1303+
*/
1304+
dev->ports[port].pvid = pvid;
1305+
new_pvid = b53_default_pvid(dev);
1306+
} else if (!dev->vlan_filtering_enabled && vlan_filtering) {
1307+
/* Filtering is currently disabled, restore the previous PVID */
1308+
new_pvid = dev->ports[port].pvid;
1309+
}
1310+
1311+
if (pvid != new_pvid)
1312+
b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port),
1313+
new_pvid);
1314+
1315+
b53_enable_vlan(dev, dev->vlan_enabled, vlan_filtering);
1316+
12681317
return 0;
12691318
}
12701319
EXPORT_SYMBOL(b53_vlan_filtering);
@@ -1280,7 +1329,7 @@ int b53_vlan_prepare(struct dsa_switch *ds, int port,
12801329
if (vlan->vid_end > dev->num_vlans)
12811330
return -ERANGE;
12821331

1283-
b53_enable_vlan(dev, true);
1332+
b53_enable_vlan(dev, true, dev->vlan_filtering_enabled);
12841333

12851334
return 0;
12861335
}

drivers/net/dsa/b53/b53_priv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ enum {
9191
struct b53_port {
9292
u16 vlan_ctl_mask;
9393
struct ethtool_eee eee;
94+
u16 pvid;
9495
};
9596

9697
struct b53_vlan {
@@ -137,6 +138,8 @@ struct b53_device {
137138

138139
unsigned int num_vlans;
139140
struct b53_vlan *vlans;
141+
bool vlan_enabled;
142+
bool vlan_filtering_enabled;
140143
unsigned int num_ports;
141144
struct b53_port *ports;
142145
};

0 commit comments

Comments
 (0)