diff --git a/drivers/net/dsa/mv88e6171.c b/drivers/net/dsa/mv88e6171.c index 54aa00012dd0ce5ca36427c0cfb41f773ea47138..6e18213b9c04434a1feaae0c87da255859632732 100644 --- a/drivers/net/dsa/mv88e6171.c +++ b/drivers/net/dsa/mv88e6171.c @@ -103,6 +103,8 @@ struct dsa_switch_driver mv88e6171_switch_driver = { #endif .get_regs_len = mv88e6xxx_get_regs_len, .get_regs = mv88e6xxx_get_regs, + .port_join_bridge = mv88e6xxx_port_bridge_join, + .port_leave_bridge = mv88e6xxx_port_bridge_leave, .port_stp_update = mv88e6xxx_port_stp_update, .port_pvid_get = mv88e6xxx_port_pvid_get, .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c index ff846d0cfcebeff1b332b8f8ae1ca48d106c667d..cc6c5455341839eb91ba55dfd23e96e954c41fb7 100644 --- a/drivers/net/dsa/mv88e6352.c +++ b/drivers/net/dsa/mv88e6352.c @@ -323,6 +323,8 @@ struct dsa_switch_driver mv88e6352_switch_driver = { .set_eeprom = mv88e6352_set_eeprom, .get_regs_len = mv88e6xxx_get_regs_len, .get_regs = mv88e6xxx_get_regs, + .port_join_bridge = mv88e6xxx_port_bridge_join, + .port_leave_bridge = mv88e6xxx_port_bridge_leave, .port_stp_update = mv88e6xxx_port_stp_update, .port_pvid_get = mv88e6xxx_port_pvid_get, .port_vlan_prepare = mv88e6xxx_port_vlan_prepare, diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c index 04cff58d771bd5a86f3b2a0bf2a047de1ee4b6f4..b06dba05594aaeb79988487bc431412b3dfae2c4 100644 --- a/drivers/net/dsa/mv88e6xxx.c +++ b/drivers/net/dsa/mv88e6xxx.c @@ -1462,6 +1462,10 @@ int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan, struct switchdev_trans *trans) { + /* We reserve a few VLANs to isolate unbridged ports */ + if (vlan->vid_end >= 4000) + return -EOPNOTSUPP; + /* We don't need any dynamic resource from the kernel (yet), * so skip the prepare phase. */ @@ -1870,6 +1874,36 @@ int mv88e6xxx_port_fdb_dump(struct dsa_switch *ds, int port, return err; } +int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + 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) +{ + struct mv88e6xxx_priv_state *ps = ds_to_priv(ds); + const u16 pvid = 4000 + ds->index * DSA_MAX_PORTS + port; + int err; + + /* The port left the bridge, so join its reserved VLAN */ + mutex_lock(&ps->smi_mutex); + err = _mv88e6xxx_port_vlan_add(ds, port, pvid, true); + if (!err) + err = _mv88e6xxx_port_pvid_set(ds, port, pvid); + mutex_unlock(&ps->smi_mutex); + return err; +} + static void mv88e6xxx_bridge_work(struct work_struct *work) { struct mv88e6xxx_priv_state *ps; @@ -2140,6 +2174,14 @@ int mv88e6xxx_setup_ports(struct dsa_switch *ds) ret = mv88e6xxx_setup_port(ds, i); if (ret < 0) return ret; + + if (dsa_is_cpu_port(ds, i) || dsa_is_dsa_port(ds, i)) + continue; + + /* setup the unbridged state */ + ret = mv88e6xxx_port_bridge_leave(ds, i, 0); + if (ret < 0) + return ret; } return 0; } diff --git a/drivers/net/dsa/mv88e6xxx.h b/drivers/net/dsa/mv88e6xxx.h index fb9a8739712f3cfc8a4f1736d594d221dedeeb89..21c8daa03f788e369caa9eb2fe12c764607acd62 100644 --- a/drivers/net/dsa/mv88e6xxx.h +++ b/drivers/net/dsa/mv88e6xxx.h @@ -468,6 +468,8 @@ int mv88e6xxx_phy_write_indirect(struct dsa_switch *ds, int addr, int regnum, int mv88e6xxx_get_eee(struct dsa_switch *ds, int port, struct ethtool_eee *e); int mv88e6xxx_set_eee(struct dsa_switch *ds, int port, struct phy_device *phydev, struct ethtool_eee *e); +int mv88e6xxx_port_bridge_join(struct dsa_switch *ds, int port, u32 members); +int mv88e6xxx_port_bridge_leave(struct dsa_switch *ds, int port, u32 members); int mv88e6xxx_port_stp_update(struct dsa_switch *ds, int port, u8 state); int mv88e6xxx_port_vlan_prepare(struct dsa_switch *ds, int port, const struct switchdev_obj_port_vlan *vlan,