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: a2482d2ce3
("net: dsa: b53: Plug in VLAN support")
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
fea8335317
commit
dad8d7c645
|
@ -344,7 +344,8 @@ static void b53_set_forwarding(struct b53_device *dev, int enable)
|
|||
b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_CTRL, mgmt);
|
||||
}
|
||||
|
||||
static void b53_enable_vlan(struct b53_device *dev, bool enable)
|
||||
static void b53_enable_vlan(struct b53_device *dev, bool enable,
|
||||
bool enable_filtering)
|
||||
{
|
||||
u8 mgmt, vc0, vc1, vc4 = 0, vc5;
|
||||
|
||||
|
@ -369,8 +370,13 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable)
|
|||
vc0 |= VC0_VLAN_EN | VC0_VID_CHK_EN | VC0_VID_HASH_VID;
|
||||
vc1 |= VC1_RX_MCST_UNTAG_EN | VC1_RX_MCST_FWD_EN;
|
||||
vc4 &= ~VC4_ING_VID_CHECK_MASK;
|
||||
vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
|
||||
vc5 |= VC5_DROP_VTABLE_MISS;
|
||||
if (enable_filtering) {
|
||||
vc4 |= VC4_ING_VID_VIO_DROP << VC4_ING_VID_CHECK_S;
|
||||
vc5 |= VC5_DROP_VTABLE_MISS;
|
||||
} else {
|
||||
vc4 |= VC4_ING_VID_VIO_FWD << VC4_ING_VID_CHECK_S;
|
||||
vc5 &= ~VC5_DROP_VTABLE_MISS;
|
||||
}
|
||||
|
||||
if (is5325(dev))
|
||||
vc0 &= ~VC0_RESERVED_1;
|
||||
|
@ -420,6 +426,9 @@ static void b53_enable_vlan(struct b53_device *dev, bool enable)
|
|||
}
|
||||
|
||||
b53_write8(dev, B53_CTRL_PAGE, B53_SWITCH_MODE, mgmt);
|
||||
|
||||
dev->vlan_enabled = enable;
|
||||
dev->vlan_filtering_enabled = enable_filtering;
|
||||
}
|
||||
|
||||
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)
|
|||
b53_do_vlan_op(dev, VTA_CMD_CLEAR);
|
||||
}
|
||||
|
||||
b53_enable_vlan(dev, false);
|
||||
b53_enable_vlan(dev, false, dev->vlan_filtering_enabled);
|
||||
|
||||
b53_for_each_port(dev, i)
|
||||
b53_write16(dev, B53_VLAN_PAGE,
|
||||
|
@ -1265,6 +1274,46 @@ EXPORT_SYMBOL(b53_phylink_mac_link_up);
|
|||
|
||||
int b53_vlan_filtering(struct dsa_switch *ds, int port, bool vlan_filtering)
|
||||
{
|
||||
struct b53_device *dev = ds->priv;
|
||||
struct net_device *bridge_dev;
|
||||
unsigned int i;
|
||||
u16 pvid, new_pvid;
|
||||
|
||||
/* Handle the case were multiple bridges span the same switch device
|
||||
* and one of them has a different setting than what is being requested
|
||||
* which would be breaking filtering semantics for any of the other
|
||||
* bridge devices.
|
||||
*/
|
||||
b53_for_each_port(dev, i) {
|
||||
bridge_dev = dsa_to_port(ds, i)->bridge_dev;
|
||||
if (bridge_dev &&
|
||||
bridge_dev != dsa_to_port(ds, port)->bridge_dev &&
|
||||
br_vlan_enabled(bridge_dev) != vlan_filtering) {
|
||||
netdev_err(bridge_dev,
|
||||
"VLAN filtering is global to the switch!\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
b53_read16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port), &pvid);
|
||||
new_pvid = pvid;
|
||||
if (dev->vlan_filtering_enabled && !vlan_filtering) {
|
||||
/* Filtering is currently enabled, use the default PVID since
|
||||
* the bridge does not expect tagging anymore
|
||||
*/
|
||||
dev->ports[port].pvid = pvid;
|
||||
new_pvid = b53_default_pvid(dev);
|
||||
} else if (!dev->vlan_filtering_enabled && vlan_filtering) {
|
||||
/* Filtering is currently disabled, restore the previous PVID */
|
||||
new_pvid = dev->ports[port].pvid;
|
||||
}
|
||||
|
||||
if (pvid != new_pvid)
|
||||
b53_write16(dev, B53_VLAN_PAGE, B53_VLAN_PORT_DEF_TAG(port),
|
||||
new_pvid);
|
||||
|
||||
b53_enable_vlan(dev, dev->vlan_enabled, vlan_filtering);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(b53_vlan_filtering);
|
||||
|
@ -1280,7 +1329,7 @@ int b53_vlan_prepare(struct dsa_switch *ds, int port,
|
|||
if (vlan->vid_end > dev->num_vlans)
|
||||
return -ERANGE;
|
||||
|
||||
b53_enable_vlan(dev, true);
|
||||
b53_enable_vlan(dev, true, dev->vlan_filtering_enabled);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -91,6 +91,7 @@ enum {
|
|||
struct b53_port {
|
||||
u16 vlan_ctl_mask;
|
||||
struct ethtool_eee eee;
|
||||
u16 pvid;
|
||||
};
|
||||
|
||||
struct b53_vlan {
|
||||
|
@ -137,6 +138,8 @@ struct b53_device {
|
|||
|
||||
unsigned int num_vlans;
|
||||
struct b53_vlan *vlans;
|
||||
bool vlan_enabled;
|
||||
bool vlan_filtering_enabled;
|
||||
unsigned int num_ports;
|
||||
struct b53_port *ports;
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue