繁体   English   中英

大型 PCIe DMA Linux x86-64

[英]Large PCIe DMA Linux x86-64

我正在使用高速串行卡从外部源到带有 PCIe 卡的 Linux 机器进行高速数据传输。 PCIe 卡带有一些 3rd 方驱动程序,它们使用 dma_alloc_coherent 来分配 dma 缓冲区以接收数据。 然而,由于 Linux 的限制,这种方法将数据传输限制为 4MB。 我一直在阅读和尝试多种方法来分配一个大的 DMA 缓冲区,但一直无法让一个工作。

这个系统有 32GB 的内存,运行 Red Hat,内核版本为 3.10,我想为连续的 DMA 提供 4GB 的内存。 我知道首选方法是分散/收集,但在我的情况下这是不可能的,因为有一个硬件芯片可以将串行协议转换为我无法控制的 DMA,我唯一可以控制的就是向传入地址(即,从外部系统看到的地址零可以映射到本地总线上的地址 0x700000000)。

由于这是一台一次性的实验室机器,我认为最快/最简单的方法是使用 mem=28GB 启动配置参数。 我的这个工作正常,但是从虚拟空间访问该内存的下一步是我遇到问题的地方。 这是我浓缩为相关组件的代码:

在内核模块中:

size_t len = 0x100000000ULL; // 4GB
size_t phys = 0x700000000ULL; // 28GB
size_t virt = ioremap_nocache( phys, len ); // address not usable via direct reference
size_t bus = (size_t)virt_to_bus( (void*)virt ); // this should be the same as phys for x86-64, shouldn't it?

// OLD WAY
/*size_t len = 0x400000; // 4MB
size_t bus;
size_t virt = dma_alloc_coherent( devHandle, len, &bus, GFP_ATOMIC );
size_t phys = (size_t)virt_to_phys( (void*)virt );*/

在应用程序中:

// Attempt to make a usable virtual pointer
u32 pSize = sysconf(_SC_PAGESIZE);
void* mapAddr = mmap(0, len+(phys%pSize), PROT_READ|PROT_WRITE, MAP_SHARED, devHandle, phys-(phys%pSize));
virt = (size_t)mapAddr + (phys%pSize);

// do DMA to 0x700000000 bus address

printf("Value %x\n", *((u32*)virt)); // this is returning zero

另一个有趣的事情是,在执行所有这些操作之前,从 dma_alloc_coherent 返回的物理地址大于系统上的 RAM 量(0x83d000000)。 我认为在 x86 中 RAM 将始终是最低地址,因此我希望地址小于 32GB。

任何帮助,将不胜感激。

不要通过mem限制系统内存量,而是尝试使用 CMA: https : //lwn.net/Articles/486301/

使用 CMA 内核命令行参数可以为保证连续的 DMA 操作保留一定数量的内存。 内核将允许非 DMA 进程访问该内存,但是一旦 DMA 操作需要该内存,非 DMA 进程将被逐出。 因此,我建议不要更改您的mem参数,而是将cma=4G添加到您的 cmdline 中。 dma_alloc_coherent应该自动从该保留空间中提取,但您可以在内核配置中启用 CMA 调试以确保。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM