繁体   English   中英

Linux PCIe DMA驱动程序(Xilinx XDMA)

[英]Linux PCIe DMA Driver (Xilinx XDMA)

我目前正在使用Xilinx XDMA驱动程序(请参阅此处获取源代码: XDMA Source ),并且我试图让它运行(在您提出之前:我已经联系了我的技术支持联系人,Xilinx论坛上充斥着人们有同样的问题)。 但是,我可能在Xilinx的代码中找到了一个障碍,这对我来说可能是一个交易破坏者。 我希望有一些我不会考虑的事情。

首先,驱动程序有两种主要模式,AXI-Memory Mapped(AXI-MM)和AXI-Streaming(AXI-ST)。 对于我的特定应用,我需要AXI-ST,因为数据将持续从设备流出。

编写驱动程序以利用分散 - 收集列表。 在AXI-MM模式下,这是有效的,因为读取是相当随机的事件(即,没有数据流出设备,而用户空间应用程序只是在需要时请求数据)。 因此,建立DMA传输,传输数据,然后拆除传输。 这是get_user_pages()pci_map_sg()pci_unmap_sg()

对于AXI-ST来说,事情变得奇怪,源代码远非正统。 驱动程序分配一个循环缓冲区,数据意味着连续流入。 此缓冲区的大小通常有些大(我的设置大小为32MB),因为您希望能够处理用户空间应用程序忘记驱动程序的瞬态事件,然后可以解决传入的数据。

事情变得困难......循环缓冲区使用vmalloc32()分配,并且该分配的页面映射方式与用户空间缓冲区处于AXI-MM模式(即使用pci_map_sg()接口)的方式相同。 因此,因为循环缓冲区在设备和CPU之间共享,所以每次read()调用都要求我调用pci_dma_sync_sg_for_cpu()pci_dma_sync_sg_for_device() ,这绝对会破坏我的性能(我无法跟上设备!),因为这适用于整个缓冲区。 有趣的是,Xilinx从未在代码中包含这些同步调用,因此我首先知道在编辑测试脚本以在退出之前尝试多个DMA传输并且生成的数据缓冲区已损坏时,我遇到了问题。

结果,我想知道如何解决这个问题。 我已经考虑过重写代码来构建我自己使用pci_alloc_consistent()/dma_alloc_coherent()分配的缓冲区,但这说起来容易做起来pci_alloc_consistent()/dma_alloc_coherent() 也就是说,代码被设计为假设在任何地方使用分散 - 收集列表(在分散 - 收集列表和FPGA理解的内存描述符之间似乎存在奇怪的专有映射)。

我应该注意其他任何API调用吗? 我可以通过一些转换机制使用“单个”变体(即pci dma_sync_single_for_cpu() )来不同步整个缓冲区吗? 或者,是否有一些函数可以使用vmalloc()分配的循环缓冲区连贯?

好吧,我明白了。

基本上,我对同步API的内核文档的假设和/或理解是完全错误的。 也就是说,我在两个关键假设上错了:

  1. 如果CPU从未写入缓冲区,则无需为设备同步。 删除此调用会使read()吞吐量翻倍。
  2. 您无需同步整个散点列表。 相反,现在在我的read()调用中,我弄清楚哪些页面将受到copy_to_user()调用的影响(即,什么将被复制出循环缓冲区)并且只同步那些我关心的页面。 基本上,我可以调用像pci_dma_sync_sg_for_cpu(lro->pci_dev, &transfer->sgm->sgl[sgl_index], pages_to_sync, DMA_FROM_DEVICE)地方,其中sgl_index是我认为副本将开始的地方, pages_to_sync是数据的数量有多大页面。

通过以上两个更改,我的代码现在符合我的吞吐量要求。

我认为XDMA最初是为x86编写的,在这种情况下,同步功能什么都不做。

除非修改循环缓冲区,否则您似乎不太可能使用单个同步变体。 用一个缓冲区列表替换循环缓冲区对我来说似乎是一个好主意。 您预先分配了许多此类缓冲区,并有一个要发送的缓冲区列表和一个供您重复使用的应用程序的空闲列表。

如果您使用的是Zynq FPGA,则可以将DMA引擎连接到ACP端口,以便FPGA内存访问一致。 或者,您可以将内存区域映射为未缓存/缓冲而不是缓存。

最后,在我的FPGA应用程序中,我将控制寄存器和缓冲区映射到应用程序进程中,并且只在驱动程序中实现mmap()和poll(),以便为应用程序提供更多的DMA执行灵活性。 我通常实现自己的DMA引擎。

Pete,我是驱动程序代码的原始开发人员(在XMDA X出现之前)。

ringbuffer总是一个非正统的东西,确实意味着缓存一致系统,默认情况下禁用。 它的最初目的是摆脱DMA(重新)启动延迟; 即使有完全的异步I / O支持(即使在某些情况下使用零延迟描述符链接),我们也有使用这种情况,这是无法保证的,并且需要真正的硬件环缓冲/循环/循环模式。

Linux中没有等效的ringbuffer API,所以它是开放式编码的。

我很高兴重新考虑IP /驱动程序设计。

你可以分享你的修复吗?

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM