2015-11-20 61 views
8

我正在使用高速串行卡进行从外部源到具有PCIe卡的Linux机箱的高速数据传输。 PCIe卡附带一些使用dma_alloc_coherent分配dma缓冲区以接收数据的第三方驱动程序。但是,由于Linux限制,这种方法将数据传输限制为4MB。我一直在阅读和尝试多种分配大型DMA缓冲区的方法,但无法让其工作。Large PCIe DMA Linux x86-64

这个系统有32GB的内存,正在运行红帽3.10的内核版本,我想让4GB的可用于连续的DMA。我知道首选的方法是分散/聚集,但在我的情况下这是不可能的,因为有一个硬件芯片将串行协议转换成超出我的控制范围的DMA,在那里我唯一可以控制的是向传入地址(即从外部系统看到的地址0可映射到本地总线上的地址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);*/ 

中的应用:

​​

另一个有趣的事情是,在做这一切之前,物理从dma_alloc_coherent返回的地址大于系统上的RAM数量(0x83d000000)。我认为在x86中RAM总是最低的地址,因此我预计地址小于32GB。

任何帮助,将不胜感激。

+1

Err ...'0x770000000ULL'是29.75 GB,而不是28 ...而是尝试'0x700000000'。 –

+0

涂料,愚蠢的数学错误。仍然应该不重要,因为该区域应该仍然是有效的RAM。我还没有上到4GB的测试案例,仍然只使用4MB。将更新问题。 – LINEMAN78

+0

我有一个方便的32GB内存系统。你可以发布一个绝对准系统,但完整的内核模块源文件,以及绝对最低限度的usermode程序来测试?另外,为什么你在Linux内核专用[c]时用[C++]标记,并且你展示的usermode片段只使用C API? –

回答

0

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

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