在linux x86_64系统上为DMA使用大缓冲区

在linux x86_64系统上为DMA使用大缓冲区,linux,linux-kernel,driver,x86-64,dma,Linux,Linux Kernel,Driver,X86 64,Dma,我正在为将移动大量数据的光纤通道卡编写设备驱动程序。该卡可以作为PCI主控卡,并将数据DMA到系统内存中。这是在运行内核3.0.35的x86_64 linux系统上实现的 我首先尝试使用kmalloc()分配缓冲区,但发现无法分配足够大的缓冲区。然而,作为一个学习练习,我继续使用kmalloc()分配的小缓冲区进行开发。我让司机在这种情况下工作。我用kmalloc()和GFP_DMA标志分配了小缓冲区,将kmalloc返回的地址传递给DMA_map_single(),并将返回的地址返回到卡上的寄

我正在为将移动大量数据的光纤通道卡编写设备驱动程序。该卡可以作为PCI主控卡,并将数据DMA到系统内存中。这是在运行内核3.0.35的x86_64 linux系统上实现的

我首先尝试使用kmalloc()分配缓冲区,但发现无法分配足够大的缓冲区。然而,作为一个学习练习,我继续使用kmalloc()分配的小缓冲区进行开发。我让司机在这种情况下工作。我用kmalloc()和GFP_DMA标志分配了小缓冲区,将kmalloc返回的地址传递给DMA_map_single(),并将返回的地址返回到卡上的寄存器

我现在正试图修改驱动程序以使用大的缓冲区——大约200MB。我在启动时使用mem=kernel参数保留了一块内存。我使用ioremap()映射保留内存。我已将内存映射到用户空间,并已验证用户应用程序是否可以写入mmap ed区域,以及驱动程序是否可以使用ioremap()返回的虚拟地址读取数据。但我一直无法将主板上的DMA数据传输到我的缓冲区

我已尝试映射使用dma_map_single()分配的区域。我首先传递了从ioremap()返回的虚拟地址。我认为这是正确的地址,因为DMA-API-HOWTO文件说:

“驱动程序可以将虚拟地址X提供给 像dma_map_single()这样的接口,用于设置任何必需的IOMMU 映射并返回DMA地址Z。然后驱动程序告诉设备 执行DMA到Z,IOMMU将其映射到系统中地址Y处的缓冲区 公羊。”

但是我从卡上没有得到任何数据。我还尝试将dma_map_single()传递给该区域的物理地址,但没有成功。我尝试将dma_map_single()返回的地址写入卡寄存器,并尝试将物理地址写入寄存器。这些努力都没有奏效

有没有我错过的一步?在这种情况下,我的程序完全错误吗?卡甚至可以对我在x86_64上保留的内存区域执行dma吗

我有可能将系统升级到3.12.28内核。我知道内核支持CMA。CMA在这种情况下有效吗


非常感谢您的帮助。

请阅读。祝你好运。
Mb
是兆位
MB
是兆字节。对不起,我不是一个内核黑客,但为什么你想使用一个4年的内核?4.x为当前值。如果你想要稳定性,3.0.35离最后的3.0.x稳定内核还差得远。将3.0.101列出为在3.0.35的基础上进行了一年多的后端口错误修复。谢谢我对内核版本没有太多的控制权。我的开发机器正在运行SLES11 SP2。实际使用的机器正在运行SLES11 SP4。我也许能让他们升级到SLES12。除此之外,我在组织中几乎没有影响力。kmalloc()不是分配大型缓冲区的正确方法,尤其是对于DMA__get_dma_pages()可能是一个更好的选择。这里的回答很晚,但我最终还是回答了自己的问题w.r.t.我是如何解决这个问题的。