[OpenWrt-Devel] [PATCH v2] ar8327: add IGMP Snooping support

Álvaro Fernández Rojas noltari at gmail.com
Sun Jan 10 11:07:19 EST 2016


This add support for IGMP Snooping on atheros switches (disabled by default),
which avoids flooding the network with multicast data.

Tested on TL-WDR4300: disabling IGMP Snooping results in multicast flooding
on each specific port, enabling it back again prevents each port from
receiving all multicast packets.

Partially based on: http://patchwork.ozlabs.org/patch/418122/

Signed-off-by: Álvaro Fernández Rojas <noltari at gmail.com>
---
 v2: introduce changes suggested by Linus Lüssing
 - switch to disabled by default
 - add MLD snooping support
 - allow enabling/disabling IGMP v3, join and leave
 - add functions for controlling settings on all ports
 At least igmp_snooping, igmp_fast_join and igmp_fast_leave must be enabled
 in order to get IGMP working. MLD Snooping and IGMP v3 are optional.

 .../linux/generic/files/drivers/net/phy/ar8216.h   |   7 +
 .../linux/generic/files/drivers/net/phy/ar8327.c   | 557 +++++++++++++++++++++
 .../linux/generic/files/drivers/net/phy/ar8327.h   |  76 +++
 3 files changed, 640 insertions(+)

diff --git a/target/linux/generic/files/drivers/net/phy/ar8216.h b/target/linux/generic/files/drivers/net/phy/ar8216.h
index 14fe928..6ebfcc7 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8216.h
+++ b/target/linux/generic/files/drivers/net/phy/ar8216.h
@@ -407,6 +407,13 @@ struct ar8xxx_chip {
 			      u32 *status, enum arl_op op);
 	int (*sw_hw_apply)(struct switch_dev *dev);
 
+	int (*get_igmp_v3)(struct ar8xxx_priv *priv);
+	void (*set_igmp_v3)(struct ar8xxx_priv *priv, int enable);
+	int (*get_port_igmp)(struct ar8xxx_priv *priv, int port);
+	void (*set_port_igmp)(struct ar8xxx_priv *priv, int port, int enable);
+	int (*get_port_cfg)(struct ar8xxx_priv *priv, int port, u32 cfg);
+	void (*set_port_cfg)(struct ar8xxx_priv *priv, int port, u32 cfg, int enable);
+
 	const struct ar8xxx_mib_desc *mib_decs;
 	unsigned num_mibs;
 	unsigned mib_func;
diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.c b/target/linux/generic/files/drivers/net/phy/ar8327.c
index 90ee411..c885761 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8327.c
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.c
@@ -33,6 +33,86 @@
 extern const struct ar8xxx_mib_desc ar8236_mibs[39];
 extern const struct switch_attr ar8xxx_sw_attr_vlan[1];
 
+const struct ar8327_port_data ar8327_ports_cfg[AR8327_NUM_PORTS] = {
+	{
+		/* Port 0 */
+		.reg = AR8327_REG_FRAM_ACK_CTRL0,
+		.igmp_mld = AR8327_IGMP_MLD_EN0,
+		.igmp_join = AR8327_IGMP_JOIN_EN0,
+		.igmp_leave = AR8327_IGMP_LEAVE_EN0,
+		.eapol = AR8327_EAPOL_EN0,
+		.dhcp = AR8327_DHCP_EN0,
+		.arp_ack = AR8327_ARP_ACK_EN0,
+		.arp_req = AR8327_ARP_REQ_EN0
+	},
+	{
+		/* Port 1 */
+		.reg = AR8327_REG_FRAM_ACK_CTRL0,
+		.igmp_mld = AR8327_IGMP_MLD_EN1,
+		.igmp_join = AR8327_IGMP_JOIN_EN1,
+		.igmp_leave = AR8327_IGMP_LEAVE_EN1,
+		.eapol = AR8327_EAPOL_EN1,
+		.dhcp = AR8327_DHCP_EN1,
+		.arp_ack = AR8327_ARP_ACK_EN1,
+		.arp_req = AR8327_ARP_REQ_EN1
+	},
+	{
+		/* Port 2 */
+		.reg = AR8327_REG_FRAM_ACK_CTRL0,
+		.igmp_mld = AR8327_IGMP_MLD_EN2,
+		.igmp_join = AR8327_IGMP_JOIN_EN2,
+		.igmp_leave = AR8327_IGMP_LEAVE_EN2,
+		.eapol = AR8327_EAPOL_EN2,
+		.dhcp = AR8327_DHCP_EN2,
+		.arp_ack = AR8327_ARP_ACK_EN2,
+		.arp_req = AR8327_ARP_REQ_EN2
+	},
+	{
+		/* Port 3 */
+		.reg = AR8327_REG_FRAM_ACK_CTRL0,
+		.igmp_mld = AR8327_IGMP_MLD_EN3,
+		.igmp_join = AR8327_IGMP_JOIN_EN3,
+		.igmp_leave = AR8327_IGMP_LEAVE_EN3,
+		.eapol = AR8327_EAPOL_EN3,
+		.dhcp = AR8327_DHCP_EN3,
+		.arp_ack = AR8327_ARP_ACK_EN3,
+		.arp_req = AR8327_ARP_REQ_EN3
+	},
+	{
+		/* Port 4 */
+		.reg = AR8327_REG_FRAM_ACK_CTRL1,
+		.igmp_mld = AR8327_IGMP_MLD_EN4,
+		.igmp_join = AR8327_IGMP_JOIN_EN4,
+		.igmp_leave = AR8327_IGMP_LEAVE_EN4,
+		.eapol = AR8327_EAPOL_EN4,
+		.dhcp = AR8327_DHCP_EN4,
+		.arp_ack = AR8327_ARP_ACK_EN4,
+		.arp_req = AR8327_ARP_REQ_EN4
+	},
+	{
+		/* Port 5 */
+		.reg = AR8327_REG_FRAM_ACK_CTRL1,
+		.igmp_mld = AR8327_IGMP_MLD_EN5,
+		.igmp_join = AR8327_IGMP_JOIN_EN5,
+		.igmp_leave = AR8327_IGMP_LEAVE_EN5,
+		.eapol = AR8327_EAPOL_EN5,
+		.dhcp = AR8327_DHCP_EN5,
+		.arp_ack = AR8327_ARP_ACK_EN5,
+		.arp_req = AR8327_ARP_REQ_EN5
+	},
+	{
+		/* Port 6 */
+		.reg = AR8327_REG_FRAM_ACK_CTRL1,
+		.igmp_mld = AR8327_IGMP_MLD_EN6,
+		.igmp_join = AR8327_IGMP_JOIN_EN6,
+		.igmp_leave = AR8327_IGMP_LEAVE_EN6,
+		.eapol = AR8327_EAPOL_EN6,
+		.dhcp = AR8327_DHCP_EN6,
+		.arp_ack = AR8327_ARP_ACK_EN6,
+		.arp_req = AR8327_ARP_REQ_EN6
+	},
+};
+
 static u32
 ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg)
 {
@@ -648,6 +728,174 @@ ar8327_cleanup(struct ar8xxx_priv *priv)
 	ar8327_leds_cleanup(priv);
 }
 
+int
+ar8327_sw_get_igmp_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+
+	mutex_lock(&priv->reg_mutex);
+	for (port = 0; port < dev->ports; port++) {
+		val->value.i = priv->chip->get_port_igmp(priv, port);
+		if (!val->value.i)
+			break;
+	}
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_igmp_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+
+	mutex_lock(&priv->reg_mutex);
+	for (port = 0; port < dev->ports; port++)
+		priv->chip->set_port_igmp(priv, port, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_get_mld_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+
+	mutex_lock(&priv->reg_mutex);
+	for (port = 0; port < dev->ports; port++) {
+		val->value.i = priv->chip->get_port_cfg(priv, port, AR8327_PORT_IGMP_MLD);
+		if (!val->value.i)
+			break;
+	}
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_mld_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+
+	mutex_lock(&priv->reg_mutex);
+	for (port = 0; port < dev->ports; port++)
+		priv->chip->set_port_cfg(priv, port, AR8327_PORT_IGMP_MLD, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_get_igmp_fastjoin(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+
+	mutex_lock(&priv->reg_mutex);
+	for (port = 0; port < dev->ports; port++) {
+		val->value.i = priv->chip->get_port_cfg(priv, port, AR8327_PORT_IGMP_JOIN);
+		if (!val->value.i)
+			break;
+	}
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_igmp_fastjoin(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+
+	mutex_lock(&priv->reg_mutex);
+	for (port = 0; port < dev->ports; port++)
+		priv->chip->set_port_cfg(priv, port, AR8327_PORT_IGMP_JOIN, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_get_igmp_fastleave(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+
+	mutex_lock(&priv->reg_mutex);
+	for (port = 0; port < dev->ports; port++) {
+		val->value.i = priv->chip->get_port_cfg(priv, port, AR8327_PORT_IGMP_LEAVE);
+		if (!val->value.i)
+			break;
+	}
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_igmp_fastleave(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port;
+
+	mutex_lock(&priv->reg_mutex);
+	for (port = 0; port < dev->ports; port++)
+		priv->chip->set_port_cfg(priv, port, AR8327_PORT_IGMP_LEAVE, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_get_igmp_v3(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	val->value.i = priv->chip->get_igmp_v3(priv);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_igmp_v3(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+
+	mutex_lock(&priv->reg_mutex);
+	priv->chip->set_igmp_v3(priv, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
 static void
 ar8327_init_globals(struct ar8xxx_priv *priv)
 {
@@ -783,6 +1031,85 @@ ar8327_atu_flush_port(struct ar8xxx_priv *priv, int port)
 	return ret;
 }
 
+int
+ar8327_get_igmp_v3(struct ar8xxx_priv *priv)
+{
+	u32 val = ar8xxx_read(priv, AR8327_REG_FRAM_ACK_CTRL1);
+
+	return (val & AR8327_IGMP_V3_EN) != 0;
+}
+
+void
+ar8327_set_igmp_v3(struct ar8xxx_priv *priv, int enable)
+{
+	if (enable)
+		ar8xxx_reg_set(priv, AR8327_REG_FRAM_ACK_CTRL1, AR8327_IGMP_V3_EN);
+	else
+		ar8xxx_reg_clear(priv, AR8327_REG_FRAM_ACK_CTRL1, AR8327_IGMP_V3_EN);
+}
+
+static int
+ar8327_get_port_igmp(struct ar8xxx_priv *priv, int port)
+{
+	u32 val = ar8xxx_read(priv, AR8327_REG_FWD_CTRL1) >>
+			      AR8327_FWD_CTRL1_IGMP_S;
+
+	return (val & BIT(port)) != 0;
+}
+
+static void
+ar8327_set_port_igmp(struct ar8xxx_priv *priv, int port, int enable)
+{
+	if (enable)
+		ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1,
+			   BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S,
+			   BIT(port) << AR8327_FWD_CTRL1_IGMP_S);
+	else
+		ar8xxx_rmw(priv, AR8327_REG_FWD_CTRL1,
+			   BIT(port) << AR8327_FWD_CTRL1_IGMP_S,
+			   BIT(port) << AR8327_FWD_CTRL1_MC_FLOOD_S);
+}
+
+static u32
+ar8327_port_cfg_values(int port, u32 cfg_values)
+{
+	u32 val = 0;
+
+	if (cfg_values & AR8327_PORT_IGMP_MLD)
+		val |= ar8327_ports_cfg[port].igmp_mld;
+	if (cfg_values & AR8327_PORT_IGMP_JOIN)
+		val |= ar8327_ports_cfg[port].igmp_join;
+	if (cfg_values & AR8327_PORT_IGMP_LEAVE)
+		val |= ar8327_ports_cfg[port].igmp_leave;
+	if (cfg_values & AR8327_PORT_EAPOL)
+		val |= ar8327_ports_cfg[port].eapol;
+	if (cfg_values & AR8327_PORT_DHCP)
+		val |= ar8327_ports_cfg[port].dhcp;
+	if (cfg_values & AR8327_PORT_ARP_ACK)
+		val |= ar8327_ports_cfg[port].arp_ack;
+	if (cfg_values & AR8327_PORT_ARP_REQ)
+		val |= ar8327_ports_cfg[port].arp_req;
+
+	return val;
+}
+
+static int
+ar8327_get_port_cfg(struct ar8xxx_priv *priv, int port, u32 cfg)
+{
+	u32 val = ar8xxx_read(priv, ar8327_ports_cfg[port].reg);
+
+	return (val & ar8327_port_cfg_values(port, cfg)) != 0;
+}
+
+static void
+ar8327_set_port_cfg(struct ar8xxx_priv *priv, int port, u32 cfg, int enable)
+{
+	if (enable)
+		ar8xxx_reg_set(priv, ar8327_ports_cfg[port].reg, ar8327_port_cfg_values(port, cfg));
+	else
+		ar8xxx_reg_clear(priv, ar8327_ports_cfg[port].reg, ar8327_port_cfg_values(port, cfg));
+}
+
 static void
 ar8327_vtu_op(struct ar8xxx_priv *priv, u32 op, u32 val)
 {
@@ -1084,6 +1411,150 @@ ar8327_sw_hw_apply(struct switch_dev *dev)
 	return 0;
 }
 
+int
+ar8327_sw_get_port_igmp_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	val->value.i = priv->chip->get_port_igmp(priv, port);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_port_igmp_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	priv->chip->set_port_igmp(priv, port, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_get_port_mld_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	val->value.i = priv->chip->get_port_cfg(priv, port, AR8327_PORT_IGMP_MLD);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_port_mld_snooping(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	priv->chip->set_port_cfg(priv, port, AR8327_PORT_IGMP_MLD, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_get_port_igmp_fastjoin(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	val->value.i = priv->chip->get_port_cfg(priv, port, AR8327_PORT_IGMP_JOIN);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_port_igmp_fastjoin(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	priv->chip->set_port_cfg(priv, port, AR8327_PORT_IGMP_JOIN, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_get_port_igmp_fastleave(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	val->value.i = priv->chip->get_port_cfg(priv, port, AR8327_PORT_IGMP_LEAVE);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
+int
+ar8327_sw_set_port_igmp_fastleave(struct switch_dev *dev,
+			    const struct switch_attr *attr,
+			    struct switch_val *val)
+{
+	struct ar8xxx_priv *priv = swdev_to_ar8xxx(dev);
+	int port = val->port_vlan;
+
+	if (port >= dev->ports)
+		return -EINVAL;
+
+	mutex_lock(&priv->reg_mutex);
+	priv->chip->set_port_cfg(priv, port, AR8327_PORT_IGMP_LEAVE, val->value.i);
+	mutex_unlock(&priv->reg_mutex);
+
+	return 0;
+}
+
 static const struct switch_attr ar8327_sw_attr_globals[] = {
 	{
 		.type = SWITCH_TYPE_INT,
@@ -1144,6 +1615,46 @@ static const struct switch_attr ar8327_sw_attr_globals[] = {
 		.description = "Flush ARL table",
 		.set = ar8xxx_sw_set_flush_arl_table,
 	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_snooping",
+		.description = "Enable IGMP Snooping",
+		.set = ar8327_sw_set_igmp_snooping,
+		.get = ar8327_sw_get_igmp_snooping,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_v3",
+		.description = "Enable IGMP V3",
+		.set = ar8327_sw_set_igmp_v3,
+		.get = ar8327_sw_get_igmp_v3,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mld_snooping",
+		.description = "Enable MLD Snooping",
+		.set = ar8327_sw_set_mld_snooping,
+		.get = ar8327_sw_get_mld_snooping,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_fast_join",
+		.description = "Enable IGMP Fast Join",
+		.set = ar8327_sw_set_igmp_fastjoin,
+		.get = ar8327_sw_get_igmp_fastjoin,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_fast_leave",
+		.description = "Enable IGMP Fast Leave",
+		.set = ar8327_sw_set_igmp_fastleave,
+		.get = ar8327_sw_get_igmp_fastleave,
+		.max = 1
+	},
 };
 
 static const struct switch_attr ar8327_sw_attr_port[] = {
@@ -1174,6 +1685,38 @@ static const struct switch_attr ar8327_sw_attr_port[] = {
 		.description = "Flush port's ARL table entries",
 		.set = ar8xxx_sw_set_flush_port_arl_table,
 	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_snooping",
+		.description = "Enable port's IGMP Snooping",
+		.set = ar8327_sw_set_port_igmp_snooping,
+		.get = ar8327_sw_get_port_igmp_snooping,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "mld_snooping",
+		.description = "Enable port's MLD Snooping",
+		.set = ar8327_sw_set_port_mld_snooping,
+		.get = ar8327_sw_get_port_mld_snooping,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_fast_join",
+		.description = "Enable port's IGMP Fast Join",
+		.set = ar8327_sw_set_port_igmp_fastjoin,
+		.get = ar8327_sw_get_port_igmp_fastjoin,
+		.max = 1
+	},
+	{
+		.type = SWITCH_TYPE_INT,
+		.name = "igmp_fast_leave",
+		.description = "Enable port's IGMP Fast Leave",
+		.set = ar8327_sw_set_port_igmp_fastjoin,
+		.get = ar8327_sw_get_port_igmp_fastleave,
+		.max = 1
+	},
 };
 
 static const struct switch_dev_ops ar8327_sw_ops = {
@@ -1227,6 +1770,13 @@ const struct ar8xxx_chip ar8327_chip = {
 	.get_arl_entry = ar8327_get_arl_entry,
 	.sw_hw_apply = ar8327_sw_hw_apply,
 
+	.get_igmp_v3 = ar8327_get_igmp_v3,
+	.set_igmp_v3 = ar8327_set_igmp_v3,
+	.get_port_igmp = ar8327_get_port_igmp,
+	.set_port_igmp = ar8327_set_port_igmp,
+	.get_port_cfg = ar8327_get_port_cfg,
+	.set_port_cfg = ar8327_set_port_cfg,
+
 	.num_mibs = ARRAY_SIZE(ar8236_mibs),
 	.mib_decs = ar8236_mibs,
 	.mib_func = AR8327_REG_MIB_FUNC
@@ -1261,6 +1811,13 @@ const struct ar8xxx_chip ar8337_chip = {
 	.get_arl_entry = ar8327_get_arl_entry,
 	.sw_hw_apply = ar8327_sw_hw_apply,
 
+	.get_igmp_v3 = ar8327_get_igmp_v3,
+	.set_igmp_v3 = ar8327_set_igmp_v3,
+	.get_port_igmp = ar8327_get_port_igmp,
+	.set_port_igmp = ar8327_set_port_igmp,
+	.get_port_cfg = ar8327_get_port_cfg,
+	.set_port_cfg = ar8327_set_port_cfg,
+
 	.num_mibs = ARRAY_SIZE(ar8236_mibs),
 	.mib_decs = ar8236_mibs,
 	.mib_func = AR8327_REG_MIB_FUNC
diff --git a/target/linux/generic/files/drivers/net/phy/ar8327.h b/target/linux/generic/files/drivers/net/phy/ar8327.h
index 8d1fb3b..340ec82 100644
--- a/target/linux/generic/files/drivers/net/phy/ar8327.h
+++ b/target/linux/generic/files/drivers/net/phy/ar8327.h
@@ -98,6 +98,61 @@
 #define AR8327_REG_EEE_CTRL			0x100
 #define   AR8327_EEE_CTRL_DISABLE_PHY(_i)	BIT(4 + (_i) * 2)
 
+#define AR8327_REG_FRAM_ACK_CTRL0		0x210
+#define   AR8327_IGMP_MLD_EN0			BIT(0)
+#define   AR8327_IGMP_JOIN_EN0			BIT(1)
+#define   AR8327_IGMP_LEAVE_EN0			BIT(2)
+#define   AR8327_EAPOL_EN0			BIT(3)
+#define   AR8327_DHCP_EN0			BIT(4)
+#define   AR8327_ARP_ACK_EN0			BIT(5)
+#define   AR8327_ARP_REQ_EN0			BIT(6)
+#define   AR8327_IGMP_MLD_EN1			BIT(8)
+#define   AR8327_IGMP_JOIN_EN1			BIT(9)
+#define   AR8327_IGMP_LEAVE_EN1			BIT(10)
+#define   AR8327_EAPOL_EN1			BIT(11)
+#define   AR8327_DHCP_EN1			BIT(12)
+#define   AR8327_ARP_ACK_EN1			BIT(13)
+#define   AR8327_ARP_REQ_EN1			BIT(14)
+#define   AR8327_IGMP_MLD_EN2			BIT(16)
+#define   AR8327_IGMP_JOIN_EN2			BIT(17)
+#define   AR8327_IGMP_LEAVE_EN2			BIT(18)
+#define   AR8327_EAPOL_EN2			BIT(19)
+#define   AR8327_DHCP_EN2			BIT(20)
+#define   AR8327_ARP_ACK_EN2			BIT(21)
+#define   AR8327_ARP_REQ_EN2			BIT(22)
+#define   AR8327_IGMP_MLD_EN3			BIT(24)
+#define   AR8327_IGMP_JOIN_EN3			BIT(25)
+#define   AR8327_IGMP_LEAVE_EN3			BIT(26)
+#define   AR8327_EAPOL_EN3			BIT(27)
+#define   AR8327_DHCP_EN3			BIT(28)
+#define   AR8327_ARP_ACK_EN3			BIT(29)
+#define   AR8327_ARP_REQ_EN3			BIT(30)
+
+#define AR8327_REG_FRAM_ACK_CTRL1		0x214
+#define   AR8327_IGMP_MLD_EN4			BIT(0)
+#define   AR8327_IGMP_JOIN_EN4			BIT(1)
+#define   AR8327_IGMP_LEAVE_EN4			BIT(2)
+#define   AR8327_EAPOL_EN4			BIT(3)
+#define   AR8327_DHCP_EN4			BIT(4)
+#define   AR8327_ARP_ACK_EN4			BIT(5)
+#define   AR8327_ARP_REQ_EN4			BIT(6)
+#define   AR8327_IGMP_MLD_EN5			BIT(8)
+#define   AR8327_IGMP_JOIN_EN5			BIT(9)
+#define   AR8327_IGMP_LEAVE_EN5			BIT(10)
+#define   AR8327_EAPOL_EN5			BIT(11)
+#define   AR8327_DHCP_EN5			BIT(12)
+#define   AR8327_ARP_ACK_EN5			BIT(13)
+#define   AR8327_ARP_REQ_EN5			BIT(14)
+#define   AR8327_IGMP_MLD_EN6			BIT(16)
+#define   AR8327_IGMP_JOIN_EN6			BIT(17)
+#define   AR8327_IGMP_LEAVE_EN6			BIT(18)
+#define   AR8327_EAPOL_EN6			BIT(19)
+#define   AR8327_DHCP_EN6			BIT(20)
+#define   AR8327_ARP_ACK_EN6			BIT(21)
+#define   AR8327_ARP_REQ_EN6			BIT(22)
+#define   AR8327_IGMP_V3_EN			BIT(24)
+#define   AR8327_PPPOE_EN			BIT(25)
+
 #define AR8327_REG_PORT_VLAN0(_i)		(0x420 + (_i) * 0x8)
 #define   AR8327_PORT_VLAN0_DEF_SVID		BITS(0, 12)
 #define   AR8327_PORT_VLAN0_DEF_SVID_S		0
@@ -217,6 +272,16 @@ enum ar8327_led_pattern {
 	AR8327_LED_PATTERN_RULE,
 };
 
+enum ar8327_port_vals {
+	AR8327_PORT_IGMP_MLD = BIT(0),
+	AR8327_PORT_IGMP_JOIN = BIT(1),
+	AR8327_PORT_IGMP_LEAVE = BIT(2),
+	AR8327_PORT_EAPOL = BIT(3),
+	AR8327_PORT_DHCP = BIT(4),
+	AR8327_PORT_ARP_ACK = BIT(5),
+	AR8327_PORT_ARP_REQ = BIT(6)
+};
+
 struct ar8327_led_entry {
 	unsigned reg;
 	unsigned shift;
@@ -249,4 +314,15 @@ struct ar8327_data {
 	bool eee[AR8XXX_NUM_PHYS];
 };
 
+struct ar8327_port_data {
+	int reg;
+	u32 igmp_mld;
+	u32 igmp_join;
+	u32 igmp_leave;
+	u32 eapol;
+	u32 dhcp;
+	u32 arp_ack;
+	u32 arp_req;
+};
+
 #endif
-- 
1.9.1
_______________________________________________
openwrt-devel mailing list
openwrt-devel at lists.openwrt.org
https://lists.openwrt.org/cgi-bin/mailman/listinfo/openwrt-devel


More information about the openwrt-devel mailing list