[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20160923173751.GA1041@n2100.armlinux.org.uk>
Date: Fri, 23 Sep 2016 18:37:52 +0100
From: Russell King - ARM Linux <linux@...linux.org.uk>
To: Eric Nelson <eric@...int.com>
Cc: Eric Dumazet <edumazet@...gle.com>,
"linux-arm-kernel@...ts.infradead.org"
<linux-arm-kernel@...ts.infradead.org>,
"netdev@...r.kernel.org" <netdev@...r.kernel.org>,
Fugang Duan <fugang.duan@....com>,
Troy Kisky <troy.kisky@...ndarydevices.com>,
Otavio Salvador <otavio@...ystems.com.br>,
Simone <cjb.sw.nospam@...il.com>
Subject: Re: Alignment issues with freescale FEC driver
On Fri, Sep 23, 2016 at 10:19:50AM -0700, Eric Nelson wrote:
> Oddly, it does prevent the vast majority (90%+) of the alignment errors.
>
> I believe this is because the compiler is generating an ldm instruction
> when the ntohl() call is used, but I'm stumped about why these aren't
> generating faults:
ldm generates alignment faults when the address is not aligned to a
32-bit boundary. ldr on ARMv6+ does not.
> I don't think that's the case.
>
> # CONFIG_IPV6_GRE is not set
>
> Hmm... Instrumenting the kernel, it seems that iphdr **is** aligned on
> a 4-byte boundary.
>
> Does the ldm instruction require 8-byte alignment?
>
> There's definitely a compiler-version dependency involved here,
> since using gcc 4.9 also reduced the number of faults dramatically.
Well, I don't think it's that gcc related:
User: 0
System: 312855 (ip6_route_input+0x6c/0x1e0)
Skipped: 0
Half: 0
Word: 0
DWord: 2
Multi: 312853
c06d8998 <ip6_route_input>:
c06d89ac: e1a04000 mov r4, r0
c06d89b0: e1d489b4 ldrh r8, [r4, #148] ; 0x94
c06d89b8: e594a0a0 ldr sl, [r4, #160] ; 0xa0
c06d89cc: e08ac008 add ip, sl, r8
c06d89d4: e28c3018 add r3, ip, #24
c06d89dc: e28c7008 add r7, ip, #8
c06d89e4: e893000f ldm r3, {r0, r1, r2, r3}
c06d89ec: e24be044 sub lr, fp, #68 ; 0x44
c06d89f4: e24b5054 sub r5, fp, #84 ; 0x54
c06d89fc: e885000f stm r5, {r0, r1, r2, r3}
c06d8a04: e897000f ldm r7, {r0, r1, r2, r3}
c06d8a10: e88e000f stm lr, {r0, r1, r2, r3}
This is from:
struct flowi6 fl6 = {
.flowi6_iif = l3mdev_fib_oif(skb->dev),
.daddr = iph->daddr,
.saddr = iph->saddr,
.flowlabel = ip6_flowinfo(iph),
.flowi6_mark = skb->mark,
.flowi6_proto = iph->nexthdr,
};
specifically, I suspect, the saddr and daddr initialisations.
There's not much to get away from this - the FEC on iMX requires a
16-byte alignment for DMA addresses, which violates the network
stack's requirement for the ethernet packet to be received with a
two byte offset. So the IP header (and IPv6 headers) will always
be mis-aligned in memory, which leads to a huge number of alignment
faults.
There's not much getting away from this - the problem is not in the
networking stack, but the FEC hardware/network driver. See:
struct fec_enet_private *fep = netdev_priv(ndev);
int off;
off = ((unsigned long)skb->data) & fep->rx_align;
if (off)
skb_reserve(skb, fep->rx_align + 1 - off);
bdp->cbd_bufaddr = cpu_to_fec32(dma_map_single(&fep->pdev->dev, skb->data, FEC_ENET_RX_FRSIZE - fep->rx_align, DMA_FROM_DEVICE));
in fec_enet_new_rxbdp().
--
RMK's Patch system: http://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line: currently at 9.6Mbps down 400kbps up
according to speedtest.net.
Powered by blists - more mailing lists