在PCIE linux内核驱动程序中流式传输DMA

时间:2012-02-21 16:49:45

标签: linux drivers pci dma

我正在研究Linux内核的FPGA驱动程序。代码似乎在x86上工作正常,但在x86_64上我遇到了一些问题。我实现了流式DMA。所以它就像

get_user_pages(...);
for (...) {
    sg_set_page();
}
pci_map_sg();

但是pci_map_sg返回了0xbd285800之类的地址,这些地址未与PAGE_SIZE对齐,因此我无法发送完整的首页,因为PCIE规范说明了

  

“请求不得指定导致的地址/长度组合   内存空间访问跨越4 KB边界。“

有没有办法获得对齐的地址,还是我错过了一些重要的地方?

Source code of DMA

1 个答案:

答案 0 :(得分:3)

第一种可能的想法是进入的用户缓冲区不会在页面边界上开始。如果您的起始地址是一页的0x800字节,则第一次sg_set_page调用的偏移量将为0x800。这将产生一个以0x800结尾的DMA地址。这是正常的事情,而不是错误。

pci_map_sg合并页面时,此第一段可能大于一页。重要的是pci_map_sg产生连续的DMA可寻址内存块,但它不会产生低级PCIe事务列表。在x64上,您更有可能获得大区域,因为大多数x64平台都有IOMMU。

我处理的许多设备都有DMA引擎,允许我指定几兆字节的逻辑传输长度。通常,PCIe端点中的DMA实现负责在每个4kB边界处启动新的PCIe事务,并且程序员可以忽略该约束。如果FPGA中的资源太有限,无法处理,您可以考虑编写驱动程序代码,将Linux内存块列表转换为(更长)PCIe事务列表。