Linux PCIe DMA驱动程序(Xilinx XDMA)

It'*_*ete 6 linux driver fpga xilinx pci-e

我目前正在使用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(),但这说起来容易做起来难.也就是说,代码被设计为假设在任何地方使用分散 - 收集列表(在分散 - 收集列表和FPGA理解的内存描述符之间似乎存在奇怪的专有映射).

有没有其他API调用我应该知道?我是否可以pci dma_sync_single_for_cpu()通过某种转换机制使用"单一"变体(即)来同步整个缓冲区?或者,是否有一些函数可以使循环缓冲区分配vmalloc()相干?

It'*_*ete 7

好吧,我想通了。

基本上,我对有关同步 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_indexpages_to_sync

通过上述两项更改,我的代码现在满足了我的吞吐量要求。