mirror of https://gitee.com/openkylin/linux.git
net: dsa: mv88e6xxx: do not leave reserved VLANs
BRIDGE_VLAN_FILTERING automatically adds a newly bridged port to the VLAN with the bridge's default_pvid. The mv88e6xxx driver currently reserves VLANs 4000+ for unbridged ports isolation. When a port joins a bridge, it leaves its reserved VLAN. When a port leaves a bridge, it joins again its reserved VLAN. But if the VLAN filtering is disabled, or if this hardware VLAN is already in use, the bridged port ends up with no default VLAN, and the communication with the CPU is thus broken. To fix this, make a port join its reserved VLAN once on setup, never leave it, and restore its PVID after another one was eventually used. Signed-off-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com> Tested-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
3c06f08b65
commit
66d9cd0f54
|
@ -1582,6 +1582,7 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
|
||||||
const struct switchdev_obj_port_vlan *vlan)
|
const struct switchdev_obj_port_vlan *vlan)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
|
const u16 defpvid = 4000 + ds->index * DSA_MAX_PORTS + port;
|
||||||
u16 pvid, vid;
|
u16 pvid, vid;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
|
@ -1597,7 +1598,8 @@ int mv88e6xxx_port_vlan_del(struct dsa_switch *ds, int port,
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
|
||||||
if (vid == pvid) {
|
if (vid == pvid) {
|
||||||
err = _mv88e6xxx_port_pvid_set(ds, port, 0);
|
/* restore reserved VLAN ID */
|
||||||
|
err = _mv88e6xxx_port_pvid_set(ds, port, defpvid);
|
||||||
if (err)
|
if (err)
|
||||||
goto unlock;
|
goto unlock;
|
||||||
}
|
}
|
||||||
|
@ -1889,26 +1891,20 @@ int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port,
|
||||||
|
|
||||||
int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members)
|
int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
return 0;
|
||||||
const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
/* The port joined a bridge, so leave its reserved VLAN */
|
|
||||||
mutex_lock(&ps->smi_mutex);
|
|
||||||
err = _mv88e6xxx_port_vlan_del(ds, port, pvid);
|
|
||||||
if (!err)
|
|
||||||
err = _mv88e6xxx_port_pvid_set(ds, port, 0);
|
|
||||||
mutex_unlock(&ps->smi_mutex);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members)
|
int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mv88e6xxx_setup_port_default_vlan(struct dsa_switch *ds, int port)
|
||||||
{
|
{
|
||||||
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
struct mv88e6xxx_priv_state *ps = ds_to_priv(ds);
|
||||||
const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
|
const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
/* The port left the bridge, so join its reserved VLAN */
|
|
||||||
mutex_lock(&ps->smi_mutex);
|
mutex_lock(&ps->smi_mutex);
|
||||||
err = _mv88e6xxx_port_vlan_add(ds, port, pvid, true);
|
err = _mv88e6xxx_port_vlan_add(ds, port, pvid, true);
|
||||||
if (!err)
|
if (!err)
|
||||||
|
@ -2192,8 +2188,7 @@ int mv88e6xxx_setup_ports(struct dsa_switch *ds)
|
||||||
if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
|
if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/* setup the unbridged state */
|
ret = mv88e6xxx_setup_port_default_vlan(ds, i);
|
||||||
ret = mv88e6xxx_port_bridge_leave(ds, i, 0);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue