[meta-freescale] [PATCH V3 4/4][linux-fslc][4.1-1.0.x-imx] net: fec: align IP

Eric Nelson eric at nelint.com
Sat Sep 24 07:00:37 PDT 2016


The FEC receive accelerator (RACC) supports shifting the data payload of 
received packets by 16-bits, which aligns the payload (IP header) on a 
4-byte boundary, which is, if not required, at least strongly suggested
by the Linux networking layer.

Without this patch, a huge number of alignment faults will be taken by the
IP stack, as seen in /proc/cpu/alignment:

	~/$ cat /proc/cpu/alignment
	User:		0
	System:		72645 (inet_gro_receive+0x104/0x27c)
	Skipped:	0
	Half:		0
	Word:		0
	DWord:		0
	Multi:		72645
	User faults:	3 (fixup+warn)

This patch was suggested by Andrew Lunn in this message to linux-netdev:
	http://marc.info/?l=linux-arm-kernel&m=147465452108384&w=2

and adapted from a patch by Russell King from 2014:
	http://git.arm.linux.org.uk/cgit/linux-arm.git/commit/?id=70d8a8a

Signed-off-by: Eric Nelson <eric at nelint.com>
---
V3 uses FEC_QUIRK_HAS_RACC to test for support, since all devices with the
receive accelerator support the SHIFT16 bit. It also removes support for 
FEC_QUIRK_HAS_RACC from i.MX25 and i.MX27 which don't appear to support the
feature and separates the addition of the quirk for i.MX6UL into a separate
patch.

Note that I haven't found the reference manual for mvf600, so this should be
tested.

V2 removes code in fec_enet_copybreak() that strips the two bytes of padding
and breaks the alignment. The call to skb_pull_inline in the caller instructs
the IP stack to ignore these bytes. With V2, no alignment errors are seen.

I've only tested this patch on i.MX6UL at the moment, and encourage others using
4.1.x to try it out.

Note that there are lots of other patches in Russell's tree that deserve 
some effort in bringing up-stream and I encourage others to make use of
his work.

 drivers/net/ethernet/freescale/fec_main.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index c196275..659e1c9 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -180,6 +180,7 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
 /* FEC receive acceleration */
 #define FEC_RACC_IPDIS		(1 << 1)
 #define FEC_RACC_PRODIS		(1 << 2)
+#define FEC_RACC_SHIFT16	BIT(7)
 #define FEC_RACC_OPTIONS	(FEC_RACC_IPDIS | FEC_RACC_PRODIS)
 
 /*
@@ -985,9 +986,11 @@ fec_restart(struct net_device *ndev)
 
 #if !defined(CONFIG_M5272)
 	if (fep->quirks & FEC_QUIRK_HAS_RACC) {
-		/* set RX checksum */
 		val = readl(fep->hwp + FEC_RACC);
+		/* align IP header */
+		val |= FEC_RACC_SHIFT16;
 		if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
+			/* set RX checksum */
 			val |= FEC_RACC_OPTIONS;
 		else
 			val &= ~FEC_RACC_OPTIONS;
@@ -1443,7 +1446,6 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 	bdp = rxq->cur_rx;
 
 	while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
-
 		if (pkt_received >= budget)
 			break;
 		pkt_received++;
@@ -1504,6 +1506,12 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 		prefetch(skb->data - NET_IP_ALIGN);
 		skb_put(skb, pkt_len - 4);
 		data = skb->data;
+
+#if !defined(CONFIG_M5272)
+		if (fep->quirks & FEC_QUIRK_HAS_RACC)
+			data = skb_pull_inline(skb, 2);
+#endif
+
 		if (!is_copybreak && need_swap)
 			swap_buffer(data, pkt_len);
 
-- 
2.7.4



More information about the meta-freescale mailing list