Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f444ef51 authored by David S. Miller's avatar David S. Miller
Browse files

Merge branch 'dsa-lan9303-IGMP-handling'



Egil Hjelmeland says:

====================
net: dsa: lan9303: IGMP handling

Set up the HW switch to trap IGMP packets to CPU port.
And make sure skb->offload_fwd_mark is cleared for incoming IGMP packets.

skb->offload_fwd_mark calculation is a candidate for consolidation into the
DSA core. The calculation can probably be more polished when done at a point
where DSA has updated skb.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 940c9c45 4672cd36
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
@@ -153,6 +153,8 @@
# define LAN9303_SWE_VLAN_UNTAG_PORT0 BIT(12)
#define LAN9303_SWE_VLAN_CMD_STS 0x1810
#define LAN9303_SWE_GLB_INGRESS_CFG 0x1840
# define LAN9303_SWE_GLB_INGR_IGMP_TRAP BIT(7)
# define LAN9303_SWE_GLB_INGR_IGMP_PORT(p) BIT(10 + p)
#define LAN9303_SWE_PORT_STATE 0x1843
# define LAN9303_SWE_PORT_STATE_FORWARDING_PORT2 (0)
# define LAN9303_SWE_PORT_STATE_LEARNING_PORT2 BIT(5)
@@ -450,6 +452,21 @@ static int lan9303_read_switch_reg(struct lan9303 *chip, u16 regnum, u32 *val)
	return ret;
}

static int lan9303_write_switch_reg_mask(struct lan9303 *chip, u16 regnum,
					 u32 val, u32 mask)
{
	int ret;
	u32 reg;

	ret = lan9303_read_switch_reg(chip, regnum, &reg);
	if (ret)
		return ret;

	reg = (reg & ~mask) | val;

	return lan9303_write_switch_reg(chip, regnum, reg);
}

static int lan9303_write_switch_port(struct lan9303 *chip, int port,
				     u16 regnum, u32 val)
{
@@ -905,6 +922,15 @@ static int lan9303_setup(struct dsa_switch *ds)
	if (ret)
		dev_err(chip->dev, "failed to re-enable switching %d\n", ret);

	/* Trap IGMP to port 0 */
	ret = lan9303_write_switch_reg_mask(chip, LAN9303_SWE_GLB_INGRESS_CFG,
					    LAN9303_SWE_GLB_INGR_IGMP_TRAP |
					    LAN9303_SWE_GLB_INGR_IGMP_PORT(0),
					    LAN9303_SWE_GLB_INGR_IGMP_PORT(1) |
					    LAN9303_SWE_GLB_INGR_IGMP_PORT(2));
	if (ret)
		dev_err(chip->dev, "failed to setup IGMP trap %d\n", ret);

	return 0;
}

+13 −0
Original line number Diff line number Diff line
@@ -92,6 +92,8 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev,
{
	u16 *lan9303_tag;
	unsigned int source_port;
	u16 ether_type_nw;
	u8 ip_protocol;

	if (unlikely(!pskb_may_pull(skb, LAN9303_TAG_LEN))) {
		dev_warn_ratelimited(&dev->dev,
@@ -129,6 +131,17 @@ static struct sk_buff *lan9303_rcv(struct sk_buff *skb, struct net_device *dev,
	skb->offload_fwd_mark = !ether_addr_equal(skb->data - ETH_HLEN,
						  eth_stp_addr);

	/* We also need IGMP packets to have skb->offload_fwd_mark = 0.
	 * Solving this for all conceivable situations would add more cost to
	 * every packet. Instead we handle just the common case:
	 * No VLAN tag + Ethernet II framing.
	 * Test least probable term first.
	 */
	ether_type_nw = lan9303_tag[2];
	ip_protocol = *(skb->data + 9);
	if (ip_protocol == IPPROTO_IGMP && ether_type_nw == htons(ETH_P_IP))
		skb->offload_fwd_mark = 0;

	return skb;
}