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
---
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 = AR8