@@ -479,6 +479,8 @@ struct dsa_switch_ops {
/*
* Multicast database
*/
+ int (*port_multicast_toggle)(struct dsa_switch *ds, int port,
+ bool mc_disabled);
int (*port_mdb_prepare)(struct dsa_switch *ds, int port,
const struct switchdev_obj_port_mdb *mdb);
void (*port_mdb_add)(struct dsa_switch *ds, int port,
@@ -27,6 +27,7 @@ enum {
DSA_NOTIFIER_VLAN_ADD,
DSA_NOTIFIER_VLAN_DEL,
DSA_NOTIFIER_VLAN_FILTERING,
+ DSA_NOTIFIER_MC_DISABLED,
};
/* DSA_NOTIFIER_AGEING_TIME */
@@ -74,6 +75,14 @@ struct dsa_notifier_vlan_filtering_info {
int port;
};
+/* DSA_NOTIFIER_MC_DISABLED */
+struct dsa_notifier_mc_disabled_info {
+ bool mc_disabled;
+ struct switchdev_trans *trans;
+ int sw_index;
+ int port;
+};
+
struct dsa_slave_priv {
/* Copy of CPU port xmit for faster access in slave transmit hot path */
struct sk_buff * (*xmit)(struct sk_buff *skb,
@@ -154,6 +163,8 @@ int dsa_port_enable(struct dsa_port *dp, struct phy_device *phy);
void dsa_port_disable(struct dsa_port *dp, struct phy_device *phy);
int dsa_port_bridge_join(struct dsa_port *dp, struct net_device *br);
void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br);
+int dsa_port_multicast_toggle(struct dsa_port *dp, bool mc_disabled,
+ struct switchdev_trans *trans);
int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
struct switchdev_trans *trans);
int dsa_port_ageing_time(struct dsa_port *dp, clock_t ageing_clock,
@@ -143,6 +143,19 @@ void dsa_port_bridge_leave(struct dsa_port *dp, struct net_device *br)
dsa_port_set_state_now(dp, BR_STATE_FORWARDING);
}
+int dsa_port_multicast_toggle(struct dsa_port *dp, bool mc_disabled,
+ struct switchdev_trans *trans)
+{
+ struct dsa_notifier_mc_disabled_info info = {
+ .sw_index = dp->ds->index,
+ .port = dp->index,
+ .trans = trans,
+ .mc_disabled = mc_disabled,
+ };
+
+ return dsa_port_notify(dp, DSA_NOTIFIER_MC_DISABLED, &info);
+}
+
int dsa_port_vlan_filtering(struct dsa_port *dp, bool vlan_filtering,
struct switchdev_trans *trans)
{
@@ -337,6 +337,10 @@ 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_BRIDGE_MC_DISABLED:
+ ret = dsa_port_multicast_toggle(dp, attr->u.mc_disabled,
+ trans);
+ break;
default:
ret = -EOPNOTSUPP;
break;
@@ -261,6 +261,31 @@ static int dsa_switch_vlan_filtering(struct dsa_switch *ds,
return 0;
}
+static int dsa_switch_mc_disabled(struct dsa_switch *ds,
+ struct dsa_notifier_mc_disabled_info *info)
+{
+ struct switchdev_trans *trans = info->trans;
+ bool mc_disabled = info->mc_disabled;
+ int port = info->port;
+ int err;
+
+ if (switchdev_trans_ph_prepare(trans))
+ return ds->ops->port_multicast_toggle ? 0 : -EOPNOTSUPP;
+
+ /* Build a mask of port members */
+ bitmap_zero(ds->bitmap, ds->num_ports);
+ if (ds->index == info->sw_index)
+ set_bit(port, ds->bitmap);
+
+ for_each_set_bit(port, ds->bitmap, ds->num_ports) {
+ err = ds->ops->port_multicast_toggle(ds, port, mc_disabled);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
static int dsa_switch_event(struct notifier_block *nb,
unsigned long event, void *info)
{
@@ -298,6 +323,9 @@ static int dsa_switch_event(struct notifier_block *nb,
case DSA_NOTIFIER_VLAN_FILTERING:
err = dsa_switch_vlan_filtering(ds, info);
break;
+ case DSA_NOTIFIER_MC_DISABLED:
+ err = dsa_switch_mc_disabled(ds, info);
+ break;
default:
err = -EOPNOTSUPP;
break;
The bridge can at runtime be configured with or without IGMP snooping enabled but we were not processing the switchdev attribute that notifies about that toggle, do this now. Signed-off-by: Florian Fainelli <f.fainelli@gmail.com> --- include/net/dsa.h | 2 ++ net/dsa/dsa_priv.h | 11 +++++++++++ net/dsa/port.c | 13 +++++++++++++ net/dsa/slave.c | 4 ++++ net/dsa/switch.c | 28 ++++++++++++++++++++++++++++ 5 files changed, 58 insertions(+)