需要帮助映射Xilinx / ARM SoC上的预保留**可缓存** DMA缓冲区(Zynq 7000)

时间:2016-01-19 18:27:25

标签: linux-kernel arm dma zynq soc

我有一块基于Xilinx Zynq 7000的电路板,其FPGA架构中的外设具有DMA功能(在AXI总线上)。我们开发了一个电路,并在ARM内核上运行Linux。在硬件填充后,我们在用户空间访问DMA缓冲区时遇到性能问题。

要点:

我们在启动时预先保留了一段DRAM,用作大型DMA缓冲区。我们显然使用错误的API映射此缓冲区,因为它似乎是未缓存的,并且访问速度非常糟糕。

即使作为弹跳缓冲器使用它也会因为糟糕的性能而难以忍受。 IIUC,ARM缓存不是DMA连贯的,所以我非常感谢有关如何执行以下操作的一些见解:

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

    在询问之前,我一直在努力研究这个问题。不幸的是,这是一个ARM SoC / FPGA,关于这方面的信息非常少,所以我必须直接询问专家。

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

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

    基于对此主题的大量搜索,似乎虽然有一半的人想要使用这样的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和family不会采用预定义的地址,并希望获得PCI的设备结构。我没有这样的结构,因为这是一个没有PCI的ARM SoC。我可以手动填充这样的结构,但这有点像滥用API,而不是按预期使用它。

    BTW:这是一个环形缓冲区,我们将数据块分成不同的偏移量,但我们对齐缓存线边界,因此不存在错误共享的风险。

    万分感谢您提供任何帮助!

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

3 个答案:

答案 0 :(得分:1)

您是否尝试使用mmap()方法实现自己的char设备,将缓冲区重新映射为可缓存(通过remap_pfn_range())?

答案 1 :(得分: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驱动程序,它提供了一个ioctl,用于将转换表传送到FPGA,以便我们可以在FPGA上使用逻辑上连续的地址并将它们转换为实际的DMA地址。 portalmem使用的分配方案旨在生成紧凑的转换表。

对于PCI Express连接的FPGA,我们使用与pcieportal相同的portalmem驱动程序,而不对用户软件进行任何更改。

答案 2 :(得分:0)

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