2016-01-19 26 views
1

我有一个基于7000赛灵思ZYNQ板与在具有DMA能力的FPGA架构的外围(上赛灵思/ ARM的SoC(ZYNQ 7000)DMA缓冲区AXI总线)。我们开发了一个电路并在ARM内核上运行Linux。硬件填充后,我们遇到性能问题,从用户空间访问DMA缓冲区。需要帮助映射预先保留** **缓存上

摘要:

在启动时我们已预先保留DRAM的部分用作大DMA缓冲区。我们显然使用错误的API来映射此缓冲区,因为它看起来没有缓存,并且访问速度很糟糕。

使用它,甚至作为一个反弹缓冲是慢难以维持,由于可怕的性能。 IIUC,ARM高速缓存不连贯的DMA,所以我会很感激关于如何做到以下一些见解:

  1. 地图DRAM的一个区域到内核的虚拟地址空间,但确保它是缓存
  2. 确保将它映射到用户空间并不会产生不良影响,即使这需要我们通过我们自己的驱动程序提供mmap调用。
  3. 在执行DMA之前,从缓存层次结构中显式地使物理内存区域无效,以确保一致性。

更多信息:

我一直在试图询问之前仔细研究这个。不幸的是,这是一个ARM SoC/FPGA,这方面的信息很少,所以我必须直接询问专家。

因为这是一个系统级芯片,很多东西是硬编码的u-boot。例如,在将控制交给内核之前,内核和ramdisk被加载到DRAM中的特定位置。我们利用这个优势为DMA缓冲区预留了64MB的DRAM部分(它的确需要那么大,这就是我们预先保留它的原因)。没有任何担心内存类型冲突或内核在内存中跺脚,因为引导参数告诉内核哪个区域的DRAM可以控制。

最初,我们尝试使用ioremap将此物理地址范围映射到内核空间,但似乎标记区域不可缓存,并且访问速度非常糟糕,即使我们试图使用memcpy使其成为反弹缓冲区。我们使用/ dev/mem将其映射到用户空间中,并将memcpy的时间定义为70MB/sec左右。

基于对这个主题的大量搜索,似乎有一半的人希望像这样使用ioremap(这可能是我们从中得到的想法),ioremap不应该用于这个目的以及应该使用DMA相关的API来代替。不幸的是,似乎DMA缓冲区分配是完全动态的,我还没有想出如何告诉它,“这是一个已经分配的物理地址 - 使用它。”我看着

一号文件是这一个,但它的方式太x86和PC为中心的: https://www.kernel.org/doc/Documentation/DMA-API-HOWTO.txt

而且这个问题也是在我的搜索上面来了,但没有真正的答案: get the physical address of a buffer under Linux

望着标准要求,dma_set_mask_and_coherent和家人不会采取预先定义的地址,并希望为PCI设备结构。我没有这样的结构,因为这是没有PCI的ARM SoC。我可以手动填充这样的结构,但是这对我来说就像滥用API一样,而不是按照预期使用它。

BTW:这是一个环形缓冲区,我们DMA数据块到不同的偏移,但我们对齐缓存行边界,所以没有虚假分担风险。

非常感谢您为您提供的任何帮助!

更新:看来,如果以正常方式进行操作,ARM上不存在可缓存的DMA缓冲区。也许如果我不进行ioremap调用,该区域不会被标记为不可缓存,但是我必须弄清楚如何在ARM上进行缓存管理,这是我无法弄清楚的。其中一个问题是用户空间中的memcpy显得非常糟糕。是否有一个memcpy实现为我可以使用的未缓存内存进行了优化?也许我可以写一个。我必须弄清楚这个处理器是否有Neon。

+0

您正在使用哪个版本的Linux内核?您是否尝试过使用**连续内存分配器**?... – TheCodeArtist

+0

@ TheCodeArtist“Linux(none)3.17.0-xilinx-dirty#13 SMP PREEMPT Mon Aug 3 12:10:57 MDT 2015 armv7l GNU/Linux” 另外,我没有看过CMA。如果我能正确映射这个缓冲区,它不应该要求CMA,除非完全不可能从预保留的物理地址指定DMA缓冲区。 –

+0

获取Linux下的缓冲区的物理地址(这是来自用户空间)http://stackoverflow.com/a/28987409/1163019。对于DMA/uncached东西afaik,老实说我不记得所有的细节,并且我没有成功完成我的不同任务,但是我能从代码中看到的是我正在尝试“dma_alloc_coherent” - >“update vma-> vm_page_prot作为写通过“ - > dma_mmap_from_coherent - > remap_pfn_range。也可能是这个演示文稿的帮助? http://events.linuxfoundation.org/sites/events/files/slides/20141015-dma.pdf – auselen

回答

1

您是否尝试过与mmap()方法重新映射你的缓冲区缓存(通过remap_pfn_range()方式)实现自己的字符设备?

0

我相信你需要一个驱动程序来实现mmap(),如果你想映射被缓存。

我们使用这两设备驱动程序:portalmem和zynqportal。在Connectal Project,中,我们将用户空间软件和FPGA逻辑之间的连接称为“门户”。这些驱动程序需要dma-buf,自从Linux内核版本3.8.x以来,它一直保持稳定。

portalmem的驱动程序提供一个ioctl分配的存储器中的参考计数的块,并返回与该存储器相关联的文件描述符。该驱动程序执行dma-buf sharing。它还实现了mmap(),以便用户空间应用程序可以访问内存。

在分配时,应用程序可能会选择缓存或未缓存的内存映射。在x86上,映射总是被缓存。我们对mmap()的实现目前开始于line 173 of the portalmem driver。如果映射未缓存,则使用pgprot_writecombine()修改vma-> vm_page_prot,从而启用缓冲写入但禁用缓存。

的portalmem驱动器还提供一个ioctl无效和任选回写数据高速缓存行。

portalmem驱动程序不了解FPGA。为此,我们提供了zynqportal驱动程序,该驱动程序提供了一个将转换表传送到FPGA的ioctl,以便我们可以在FPGA上使用逻辑上连续的地址并将它们转换为实际的DMA地址。 portalmem使用的分配方案旨在生成紧凑的转换表。

我们使用相同的驱动程序portalmem与pcieportal的PCI Express连接的FPGA,而无需更改用户的软件。

+0

在x86上,所有这些都很简单。对于ARM,我一直在研究如何通过AXI协议来实现缓存一致性,但是我还没有弄清楚如何分配或映射可缓存的DMA缓冲区。一些建议(如memremap)是我有机会时需要测试的一些东西。 –

+0

对于ARM,它取决于AXI如何连接到内存基础架构。例如,在Zynq上,有5个可编程的AXI端口可用于访问处理器的DRAM。它们中的4个不会被处理器缓存窥探,所以不是缓存一致的。第五个(ACP)被窥探,因此可能是缓存一致的。内存区域需要被缓存到用户进程中。 –

0

Zynq具有neon指令,使用氖指令的memcpy的汇编代码实现,使用高速缓存边界(32字节)对齐将达到300 MB/s速率或更高。