[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