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

时间:2016-07-28 00:17:20

标签: linux linux-kernel driver x86-64 dma

我正在为光纤通道卡编写一个设备驱动程序,它将移动大量数据。该卡可以充当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的缓冲区 RAM“。

但我没有从卡片中获取任何数据。我也试过传递dma_map_single()区域的物理地址,但是没有用。我已经尝试将dma_map_single()返回的地址写入卡寄存器,我尝试将物理地址写入寄存器。这些努力都没有奏效。

我有缺失的一步吗?在这种情况下,我的程序完全错了吗?卡甚至可以像我在x86_64上预留的那样对内存区域执行DMA吗?

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

感谢任何帮助。

0 个答案:

没有答案