diff mbox series

[net-next,v2,11/12] net: dsa: b53: Add support for toggling IGMP snooping

Message ID 20190130005548.2212-12-f.fainelli@gmail.com
State Changes Requested
Delegated to: David Miller
Headers show
Series net: dsa: management mode for bcm_sf2 | expand

Commit Message

Florian Fainelli Jan. 30, 2019, 12:55 a.m. UTC
Add the required configuration knobs to honor the turning off of IGMP
snooping (typically through the bridge interface) which means that when
IGMP snooping is off, we must be flooding mutlicast since we do not get
any notifications about IGMP join/leave through the network stack
running on the bridge.

Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
---
 drivers/net/dsa/b53/b53_common.c | 68 ++++++++++++++++++++++++++++++++
 drivers/net/dsa/b53/b53_priv.h   |  2 +
 2 files changed, 70 insertions(+)
diff mbox series

Patch

diff --git a/drivers/net/dsa/b53/b53_common.c b/drivers/net/dsa/b53/b53_common.c
index 6c894ad4768a..c0c064a544b9 100644
--- a/drivers/net/dsa/b53/b53_common.c
+++ b/drivers/net/dsa/b53/b53_common.c
@@ -1640,6 +1640,73 @@  int b53_fdb_dump(struct dsa_switch *ds, int port,
 }
 EXPORT_SYMBOL(b53_fdb_dump);
 
+int b53_multicast_toggle(struct dsa_switch *ds, int port,
+			 bool mc_disabled)
+{
+	unsigned int cpu_port = dsa_to_port(ds, port)->cpu_dp->index;
+	struct b53_device *dev = ds->priv;
+	struct net_device *bridge_dev;
+	struct dsa_port *dp;
+	unsigned int i;
+	u8 port_ctrl;
+	u16 mc_ctrl;
+
+	if (is5325(dev) || is5365(dev))
+		return -EOPNOTSUPP;
+
+	/* 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. We must also take care of non-bridged ports which
+	 * expect multicast filtering to remain turned on.
+	 */
+	for (i = 0; i < ds->num_ports; i++) {
+		if (dsa_is_unused_port(ds, i) || dsa_is_cpu_port(ds, i))
+			continue;
+
+		if (i == port)
+			continue;
+
+		dp = dsa_to_port(ds, i);
+		bridge_dev = dp->bridge_dev;
+		if ((bridge_dev &&
+		     bridge_dev != dsa_to_port(ds, port)->bridge_dev &&
+		     br_multicast_enabled(bridge_dev) != !mc_disabled) ||
+		     (!bridge_dev && mc_disabled)) {
+			netdev_err(dp->slave,
+				   "MC filtering is global to the switch!\n");
+			return -EINVAL;
+		}
+	}
+
+	/* Allow CPU port to receive multicast traffic */
+	b53_read8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(cpu_port), &port_ctrl);
+	if (mc_disabled)
+		port_ctrl |= PORT_CTRL_RX_MCST_EN;
+	else
+		port_ctrl &= ~PORT_CTRL_RX_MCST_EN;
+	b53_write8(dev, B53_CTRL_PAGE, B53_PORT_CTRL(cpu_port), port_ctrl);
+
+	/* Allow port to flood multicast */
+	b53_read16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, &mc_ctrl);
+	if (mc_disabled)
+		mc_ctrl |= BIT(port);
+	else
+		mc_ctrl &= ~BIT(port);
+	b53_write16(dev, B53_CTRL_PAGE, B53_MC_FLOOD_MASK, mc_ctrl);
+
+	/* And flood IP multicast as well */
+	b53_read16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, &mc_ctrl);
+	if (mc_disabled)
+		mc_ctrl |= BIT(port);
+	else
+		mc_ctrl &= ~BIT(port);
+	b53_write16(dev, B53_CTRL_PAGE, B53_IPMC_FLOOD_MASK, mc_ctrl);
+
+	return 0;
+}
+EXPORT_SYMBOL(b53_multicast_toggle);
+
 int b53_mdb_prepare(struct dsa_switch *ds, int port,
 		    const struct switchdev_obj_port_mdb *mdb)
 {
@@ -2025,6 +2092,7 @@  static const struct dsa_switch_ops b53_switch_ops = {
 	.port_mirror_add	= b53_mirror_add,
 	.port_mirror_del	= b53_mirror_del,
 	.port_mdb_prepare	= b53_mdb_prepare,
+	.port_multicast_toggle	= b53_multicast_toggle,
 	.port_mdb_add		= b53_mdb_add,
 	.port_mdb_del		= b53_mdb_del,
 };
diff --git a/drivers/net/dsa/b53/b53_priv.h b/drivers/net/dsa/b53/b53_priv.h
index 620638ff9338..cd259fb8b00e 100644
--- a/drivers/net/dsa/b53/b53_priv.h
+++ b/drivers/net/dsa/b53/b53_priv.h
@@ -350,6 +350,8 @@  int b53_fdb_del(struct dsa_switch *ds, int port,
 		const unsigned char *addr, u16 vid);
 int b53_fdb_dump(struct dsa_switch *ds, int port,
 		 dsa_fdb_dump_cb_t *cb, void *data);
+int b53_multicast_toggle(struct dsa_switch *ds, int port,
+			 bool mc_disabled);
 int b53_mdb_prepare(struct dsa_switch *ds, int port,
 		    const struct switchdev_obj_port_mdb *mdb);
 void b53_mdb_add(struct dsa_switch *ds, int port,