linux驱动程序使用DMA从用户空间传输数据



Hi我正在尝试通过AXI总线实现一个与ARM处理器集成的FPGA加速器。FPGA加速器包括一个DMA,旨在移动输入数据(从存储器)和输出数据(到存储器)。一切都像一个裸机应用程序一样工作,但我在Linux下做这件事有问题。

其思想是用户空间进程必须提供输入数据,并且必须读取输出数据。为了解决这个问题,我正在编写一个设备驱动程序,但我被困在从虚拟地址到物理地址的地址转换上。当我给DMA输入和输出基本地址时,我只能提供对我的目的无用的虚拟地址,因为我不知道如何将其转换为物理地址。结果,我从错误的内存位置读取和写入数据。我还认为,与裸机的另一个区别是,在linux中,数据可以是碎片化的,而在裸机中,它们位于连续的内存区域中。

你有什么建议或参考来解决这些问题吗?感谢

首先,警告:不要尝试使用virt_to_phys,这是解决此问题的常见建议。源代码本身表示,这个函数(实际上是一个宏,但这不是重点)不应该用于DMA或设备驱动程序。

您应该使用的是dma_alloc族中的一个函数。最有可能的候选者是void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle, gfp_t flag),它将为您做一些事情:

  • 分配size字节的固定内存(固定可防止操作系统将内存交换到磁盘)
  • dma_handle分配一个句柄,该句柄可以强制转换为无符号整数,并作为内存的物理地址提供给硬件
  • 返回一个虚拟地址,您可以使用该地址从驱动程序中访问内存
  • 确保内存是连续的

以下是一些其他资源,所有这些资源都托管在kernel.org上:

使用通用设备的动态DMA映射
DMA映射指南
virt_to_phys和phys_to_virt函数指南(请记住,在这种情况下不应该使用它们,这只是参考。)

最新更新