blob: 72edad170962eb91f03479c7be5ff3613efea850 [file] [log] [blame] [edit]
NXP's (formerly Freescale) QorIQ LS1024A SoC (formerly known as Mindspeed
Comcerto 2000) provides fast hardware forwarding between its three Ethernet
MACs. For forwarding between an Ethernet MAC and WLAN, it depends on the ARM
CPU to pass frames between the forwarding engine called PPFE (programmable
packet forwarding engine) and the WLAN hardware connected via PCIe. Most
forwarding decisions as well as NAT are handled inside the PPFE hardware. The
role of Linux is reduced to forwarding descriptors between PPFE and the WLAN
hardware. Linux rarely accesses the data inside the Ethernet frames.
Performance can be improved by using DMA coherent memory for data buffers
because they do not require L1/L2 cache flushing, invalidation, etc. which
turned out to be expensive on the LS1024A. The PPFE driver allocates buffers
using dma_alloc_coherent() and builds an skb around it. A few changes to the
kernel were necessary to support DMA coherent skbs. We added the field
dma_coherent to struct sk_buff to indicate that the skb head is in DMA coherent
memory. skb_free_head() in skbuff.c checks for this flag and calls
dma_free_coherent() instead of put_page() or kfree() on skb->head.
dma_alloc_coherent() returns two values: (1) the CPU address which is a regular
pointer i.e. a virtual address and (2) a dma handle which is basically a
physical address that can be communicated to the hardware. For our fast
forwarding approach to work, the virtual address must be in lowmem which means
that there is a simple mapping from virtual address space to physical address
space. In many situation, dma_alloc_coherent() returns an address from the
vmalloc space which does not work for our purposes because dma_map_single()
uses virt_to_page() to map a pointer (virtual address) to a page, and
virt_to_page() does not work with addresses from the vmalloc space. For
dma_alloc_coherent() to return an address in lowmem, a few conditions need to
be met: (1) The caller needs to pass in GFP_ATOMIC for arm_dma_alloc() to
allocate memory from its atomic pool. (2) The atomic pool needs to be allocated
from CMA (CONFIG_CMA and CONFIG_DMA_CMA need to be set)
dma_free_coherent() requires the cpu address (virtual address) and the dma
handle (physical address) to be passed in. However, in our approach, the dma
handle gets lost, because we do not store it in the skb. This turns out not to
be a problem because the dma handle is not required if the memory came from the
atomic pool. Although it does work in practice, the DMA-API debug feature
complains about the incorrect dma handle passed into dma_free_coherent().
Examples of these error messages can be found below. They can be ignored.
December 9, 2015
Daniel Mentz <danielmentz@google.com>
[ 10.468709] ------------[ cut here ]------------
[ 10.473383] WARNING: CPU: 0 PID: 0 at lib/dma-debug.c:1093 check_unmap+0x695/0x84c()
[ 10.481163] NULL NULL: DMA-API: device driver tries to free DMA memory it has not allocated [device address=0x0000000000000000] [size=2048 bytes]
[ 10.494246] Modules linked in: pfe(O)
[ 10.497952] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G O 4.1.0-gfiber0+ #298
[ 10.505988] Hardware name: Generic Freescale LS1024A (Flattened Device Tree)
[ 10.513095] [<800142a5>] (unwind_backtrace) from [<80011441>] (show_stack+0x11/0x14)
[ 10.520885] [<80011441>] (show_stack) from [<803dd59b>] (dump_stack+0x6f/0x98)
[ 10.528139] [<803dd59b>] (dump_stack) from [<80020f87>] (warn_slowpath_common+0x6b/0x94)
[ 10.536270] [<80020f87>] (warn_slowpath_common) from [<80020fd3>] (warn_slowpath_fmt+0x23/0x2c)
[ 10.545009] [<80020fd3>] (warn_slowpath_fmt) from [<802097d5>] (check_unmap+0x695/0x84c)
[ 10.553139] [<802097d5>] (check_unmap) from [<80209a41>] (debug_dma_free_coherent+0x61/0x68)
[ 10.561692] [<80209a41>] (debug_dma_free_coherent) from [<7f8042eb>] (pfe_eth_poll+0x3f6/0x644 [pfe])
[ 10.571001] [<7f8042eb>] (pfe_eth_poll [pfe]) from [<7f8045e7>] (pfe_eth_low_poll+0x36/0x3c [pfe])
[ 10.580027] [<7f8045e7>] (pfe_eth_low_poll [pfe]) from [<8031be17>] (net_rx_action+0x153/0x240)
[ 10.588759] [<8031be17>] (net_rx_action) from [<800233d1>] (__do_softirq+0xd5/0x294)
[ 10.596541] [<800233d1>] (__do_softirq) from [<80023813>] (irq_exit+0x8f/0xd8)
[ 10.603803] [<80023813>] (irq_exit) from [<8004b4a1>] (__handle_domain_irq+0x49/0x84)
[ 10.611670] [<8004b4a1>] (__handle_domain_irq) from [<800092ef>] (gic_handle_irq+0x27/0x50)
[ 10.620069] [<800092ef>] (gic_handle_irq) from [<803e1b3f>] (__irq_svc+0x3f/0x88)
[ 10.627573] Exception stack(0x80631f58 to 0x80631fa0)
[ 10.632649] 1f40: 00000000 80633350
[ 10.640861] 1f60: 00000000 00000000 80630000 806324e8 80632400 8069b6b4 806324a0 8062a304
[ 10.649064] 1f80: 803e6a00 8069b6b4 8063003c 80631fa0 8000f14b 8000f14c 40070033 ffffffff
[ 10.657285] [<803e1b3f>] (__irq_svc) from [<8000f14c>] (arch_cpu_idle+0x30/0x34)
[ 10.664728] [<8000f14c>] (arch_cpu_idle) from [<80045fdb>] (cpu_startup_entry+0x11f/0x204)
[ 10.673035] [<80045fdb>] (cpu_startup_entry) from [<805dba31>] (start_kernel+0x309/0x314)
[ 10.681244] ---[ end trace 62a3b00cc739c0de ]---
[ 11.212979] ------------[ cut here ]------------
[ 11.217643] WARNING: CPU: 0 PID: 0 at lib/dma-debug.c:509 add_dma_entry+0xb1/0xd4()
[ 11.225323] DMA-API: exceeded 7 overlapping mappings of cacheline 0x03e00000
[ 11.232390] Modules linked in: pfe(O)
[ 11.236094] CPU: 0 PID: 0 Comm: swapper/0 Tainted: G W O 4.1.0-gfiber0+ #298
[ 11.244121] Hardware name: Generic Freescale LS1024A (Flattened Device Tree)
[ 11.251216] [<800142a5>] (unwind_backtrace) from [<80011441>] (show_stack+0x11/0x14)
[ 11.258994] [<80011441>] (show_stack) from [<803dd59b>] (dump_stack+0x6f/0x98)
[ 11.266247] [<803dd59b>] (dump_stack) from [<80020f87>] (warn_slowpath_common+0x6b/0x94)
[ 11.274366] [<80020f87>] (warn_slowpath_common) from [<80020fd3>] (warn_slowpath_fmt+0x23/0x2c)
[ 11.283094] [<80020fd3>] (warn_slowpath_fmt) from [<80208efd>] (add_dma_entry+0xb1/0xd4)
[ 11.291283] [<80208efd>] (add_dma_entry) from [<7f801861>] (pfe_hif_rx_poll+0x1c8/0x594 [pfe])
[ 11.299949] [<7f801861>] (pfe_hif_rx_poll [pfe]) from [<8031be17>] (net_rx_action+0x153/0x240)
[ 11.308593] [<8031be17>] (net_rx_action) from [<800233d1>] (__do_softirq+0xd5/0x294)
[ 11.316363] [<800233d1>] (__do_softirq) from [<80023813>] (irq_exit+0x8f/0xd8)
[ 11.323616] [<80023813>] (irq_exit) from [<8004b4a1>] (__handle_domain_irq+0x49/0x84)
[ 11.331474] [<8004b4a1>] (__handle_domain_irq) from [<800092ef>] (gic_handle_irq+0x27/0x50)
[ 11.339863] [<800092ef>] (gic_handle_irq) from [<803e1b3f>] (__irq_svc+0x3f/0x88)
[ 11.347366] Exception stack(0x80631f58 to 0x80631fa0)
[ 11.352433] 1f40: 00000000 80633350
[ 11.360636] 1f60: 00000000 00000000 80630000 806324e8 80632400 8069b6b4 806324a0 8062a304
[ 11.368838] 1f80: 803e6a00 8069b6b4 8063003c 80631fa0 8000f14b 8000f14c 400f0033 ffffffff
[ 11.377049] [<803e1b3f>] (__irq_svc) from [<8000f14c>] (arch_cpu_idle+0x30/0x34)
[ 11.384480] [<8000f14c>] (arch_cpu_idle) from [<80045fdb>] (cpu_startup_entry+0x11f/0x204)
[ 11.392776] [<80045fdb>] (cpu_startup_entry) from [<805dba31>] (start_kernel+0x309/0x314)
[ 11.400978] ---[ end trace 62a3b00cc739c0df ]---