diff options
-rw-r--r-- | drivers/net/dsa/mv88e6xxx/chip.c | 17 | ||||
-rw-r--r-- | include/net/dsa.h | 2 | ||||
-rw-r--r-- | net/dsa/dsa_priv.h | 2 | ||||
-rw-r--r-- | net/dsa/port.c | 33 | ||||
-rw-r--r-- | net/dsa/slave.c | 9 |
5 files changed, 60 insertions, 3 deletions
diff --git a/drivers/net/dsa/mv88e6xxx/chip.c b/drivers/net/dsa/mv88e6xxx/chip.c index 32e7af5caa69..cc7ce06b6d58 100644 --- a/drivers/net/dsa/mv88e6xxx/chip.c +++ b/drivers/net/dsa/mv88e6xxx/chip.c @@ -4692,6 +4692,22 @@ static int mv88e6xxx_port_mdb_del(struct dsa_switch *ds, int port, return err; } +static int mv88e6xxx_port_egress_floods(struct dsa_switch *ds, int port, + bool unicast, bool multicast) +{ + struct mv88e6xxx_chip *chip = ds->priv; + int err = -EOPNOTSUPP; + + mutex_lock(&chip->reg_lock); + if (chip->info->ops->port_set_egress_floods) + err = chip->info->ops->port_set_egress_floods(chip, port, + unicast, + multicast); + mutex_unlock(&chip->reg_lock); + + return err; +} + static const struct dsa_switch_ops mv88e6xxx_switch_ops = { #if IS_ENABLED(CONFIG_NET_DSA_LEGACY) .probe = mv88e6xxx_drv_probe, @@ -4719,6 +4735,7 @@ static const struct dsa_switch_ops mv88e6xxx_switch_ops = { .set_ageing_time = mv88e6xxx_set_ageing_time, .port_bridge_join = mv88e6xxx_port_bridge_join, .port_bridge_leave = mv88e6xxx_port_bridge_leave, + .port_egress_floods = mv88e6xxx_port_egress_floods, .port_stp_state_set = mv88e6xxx_port_stp_state_set, .port_fast_age = mv88e6xxx_port_fast_age, .port_vlan_filtering = mv88e6xxx_port_vlan_filtering, diff --git a/include/net/dsa.h b/include/net/dsa.h index 7f2a668ef2cc..2c2c10812814 100644 --- a/include/net/dsa.h +++ b/include/net/dsa.h @@ -400,6 +400,8 @@ struct dsa_switch_ops { void (*port_stp_state_set)(struct dsa_switch *ds, int port, u8 state); void (*port_fast_age)(struct dsa_switch *ds, int port); + int (*port_egress_floods)(struct dsa_switch *ds, int port, + bool unicast, bool multicast); /* * VLAN support diff --git a/net/dsa/dsa_priv.h b/net/dsa/dsa_priv.h index 1f4972dab9f2..f4f99ec29f5d 100644 --- a/net/dsa/dsa_priv.h +++ b/net/dsa/dsa_priv.h @@ -160,6 +160,8 @@ int dsa_port_mdb_add(const struct dsa_port *dp, struct switchdev_trans *trans); int dsa_port_mdb_del(const struct dsa_port *dp, const struct switchdev_obj_port_mdb *mdb); +int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags, + struct switchdev_trans *trans); int dsa_port_vlan_add(struct dsa_port *dp, const struct switchdev_obj_port_vlan *vlan, struct switchdev_trans *trans); diff --git a/net/dsa/port.c b/net/dsa/port.c index 2d7e01b23572..7bc2a5ad95c6 100644 --- a/net/dsa/port.c +++ b/net/dsa/port.c @@ -105,16 +105,23 @@ int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br) }; int err; - /* Here the port is already bridged. Reflect the current configuration - * so that drivers can program their chips accordingly. + /* Set the flooding mode before joining the port in the switch */ + err = dsa_port_bridge_flags(dp, BR_FLOOD | BR_MCAST_FLOOD, NULL); + if (err) + return err; + + /* Here the interface is already bridged. Reflect the current + * configuration so that drivers can program their chips accordingly. */ dp->bridge_dev = br; err = dsa_port_notify(dp, DSA_NOTIFIER_BRIDGE_JOIN, &info); /* The bridging is rolled back on error */ - if (err) + if (err) { + dsa_port_bridge_flags(dp, 0, NULL); dp->bridge_dev = NULL; + } return err; } @@ -137,6 +144,9 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br) if (err) pr_err("DSA: failed to notify DSA_NOTIFIER_BRIDGE_LEAVE\n"); + /* Port is leaving the bridge, disable flooding */ + dsa_port_bridge_flags(dp, 0, NULL); + /* Port left the bridge, put in BR_STATE_DISABLED by the bridge layer, * so allow it to be in BR_STATE_FORWARDING to be kept functional */ @@ -177,6 +187,23 @@ int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock, return dsa_port_notify(dp, DSA_NOTIFIER_AGEING_TIME, &info); } +int dsa_port_bridge_flags(const struct dsa_port *dp, unsigned long flags, + struct switchdev_trans *trans) +{ + struct dsa_switch *ds = dp->ds; + int port = dp->index; + int err = 0; + + if (switchdev_trans_ph_prepare(trans)) + return 0; + + if (ds->ops->port_egress_floods) + err = ds->ops->port_egress_floods(ds, port, flags & BR_FLOOD, + flags & BR_MCAST_FLOOD); + + return err; +} + int dsa_port_fdb_add(struct dsa_port *dp, const unsigned char *addr, u16 vid) { diff --git a/net/dsa/slave.c b/net/dsa/slave.c index 2e5e7c04821b..85dc68611002 100644 --- a/net/dsa/slave.c +++ b/net/dsa/slave.c @@ -295,6 +295,9 @@ static int dsa_slave_port_attr_set(struct net_device *dev, case SWITCHDEV_ATTR_ID_BRIDGE_AGEING_TIME: ret = dsa_port_ageing_time(dp, attr->u.ageing_time, trans); break; + case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS: + ret = dsa_port_bridge_flags(dp, attr->u.brport_flags, trans); + break; default: ret = -EOPNOTSUPP; break; @@ -381,9 +384,15 @@ static int dsa_slave_get_port_parent_id(struct net_device *dev, static int dsa_slave_port_attr_get(struct net_device *dev, struct switchdev_attr *attr) { + struct dsa_port *dp = dsa_slave_to_port(dev); + struct dsa_switch *ds = dp->ds; + switch (attr->id) { case SWITCHDEV_ATTR_ID_PORT_BRIDGE_FLAGS_SUPPORT: attr->u.brport_flags_support = 0; + if (ds->ops->port_egress_floods) + attr->u.brport_flags_support |= BR_FLOOD | + BR_MCAST_FLOOD; break; default: return -EOPNOTSUPP; |