[meta-freescale] [PATCH][linux-fslc][4.1-1.0.x-imx] net: fec: support RRACC_SHIFT16 to align IP header

Eric Nelson eric at nelint.com
Fri Sep 23 18:44:25 PDT 2016


The i.MX6 UL and DQLS variants all support shifting the data payload
of received packets by 16-bits, which aligns the IP header on a longword
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)

With this patch, I am still seeing some alignment faults, but on
the order of 10 after a 100MiB transfer instead of the 72k shown
above.

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/?h=fec-testing&id=70d8a8a

Signed-off-by: Eric Nelson <eric at nelint.com>
---
I've only tested this patch on i.MX6UL at the moment, an encourage others using
4.1.x to try it out.

I did look at the RM for the i.MX6SX and updates will be needed for that
machine because the bit appears to be in a different location.

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.h      |  4 ++++
 drivers/net/ethernet/freescale/fec_main.c | 36 +++++++++++++++++++++++++------
 2 files changed, 34 insertions(+), 6 deletions(-)

diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 65a3cd3..5ed0a5c 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -436,6 +436,7 @@ struct bufdesc_ex {
 #define FEC_QUIRK_SINGLE_MDIO		(1 << 11)
 /* Controller supports RACC register */
 #define FEC_QUIRK_HAS_RACC		(1 << 12)
+
 /*
  * i.MX6Q/DL ENET cannot wake up system in wait mode because ENET tx & rx
  * interrupt signal don't connect to GPC. So use pm qos to avoid cpu enter
@@ -443,6 +444,9 @@ struct bufdesc_ex {
  */
 #define FEC_QUIRK_BUG_WAITMODE         (1 << 13)
 
+/* Controller has ability to offset rx packets */
+#define FEC_QUIRK_RX_SHIFT16            (1 << 14)
+
 struct fec_enet_stop_mode {
 	struct regmap *gpr;
 	u8 req_gpr;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index 0f9ed22..a58d5d0 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -103,7 +103,8 @@ static struct platform_device_id fec_devtype[] = {
 		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
 				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
 				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_ERR006358 |
-				FEC_QUIRK_HAS_RACC | FEC_QUIRK_BUG_WAITMODE,
+				FEC_QUIRK_HAS_RACC | FEC_QUIRK_BUG_WAITMODE |
+				FEC_QUIRK_RX_SHIFT16,
 	}, {
 		.name = "mvf600-fec",
 		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_RACC,
@@ -118,7 +119,8 @@ static struct platform_device_id fec_devtype[] = {
 		.name = "imx6ul-fec",
 		.driver_data = FEC_QUIRK_ENET_MAC | FEC_QUIRK_HAS_GBIT |
 				FEC_QUIRK_HAS_BUFDESC_EX | FEC_QUIRK_HAS_CSUM |
-				FEC_QUIRK_HAS_VLAN,
+				FEC_QUIRK_HAS_VLAN | FEC_QUIRK_HAS_RACC |
+				FEC_QUIRK_RX_SHIFT16,
 	}, {
 		/* sentinel */
 	}
@@ -180,6 +182,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 +988,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);
+		if (fep->quirks & FEC_QUIRK_RX_SHIFT16)
+			val |= FEC_RACC_SHIFT16;
 		if (fep->csum_flags & FLAG_RX_CSUM_ENABLED)
+			/* set RX checksum */
 			val |= FEC_RACC_OPTIONS;
 		else
 			val &= ~FEC_RACC_OPTIONS;
@@ -1387,6 +1392,7 @@ static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
 {
 	struct  fec_enet_private *fep = netdev_priv(ndev);
 	struct sk_buff *new_skb;
+	unsigned char *data = (*skb)->data;
 
 	if (length > fep->rx_copybreak)
 		return false;
@@ -1395,13 +1401,25 @@ static bool fec_enet_copybreak(struct net_device *ndev, struct sk_buff **skb,
 	if (!new_skb)
 		return false;
 
+#ifndef CONFIG_M5272
+	/*
+	 * If we have enabled this feature, we need to discard
+	 * the two bytes at the beginning of the packet before
+	 * copying it.
+	 */
+	if (fep->quirks & FEC_QUIRK_RX_SHIFT16) {
+		length -= 2;
+		data += 2;
+	}
+#endif
+
 	dma_sync_single_for_cpu(&fep->pdev->dev, bdp->cbd_bufaddr,
 				FEC_ENET_RX_FRSIZE - fep->rx_align,
 				DMA_FROM_DEVICE);
 	if (!swap)
-		memcpy(new_skb->data, (*skb)->data, length);
+		memcpy(new_skb->data, data, length);
 	else
-		swap_buffer2(new_skb->data, (*skb)->data, length);
+		swap_buffer2(new_skb->data, data, length);
 	*skb = new_skb;
 
 	return true;
@@ -1420,7 +1438,6 @@ fec_enet_rx_queue(struct net_device *ndev, int budget, u16 queue_id)
 	struct bufdesc *bdp;
 	unsigned short status;
 	struct  sk_buff *skb_new = NULL;
-	struct  sk_buff *skb;
 	ushort	pkt_len;
 	__u8 *data;
 	int	pkt_received = 0;
@@ -1443,6 +1460,7 @@ 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)) {
+		struct  sk_buff *skb;
 
 		if (pkt_received >= budget)
 			break;
@@ -1504,6 +1522,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 (!is_copybreak && (fep->quirks & FEC_QUIRK_RX_SHIFT16))
+			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