LIN*_*N78 9 c++ linux redhat dma pci-e
我正在使用高速串行卡进行高速数据传输,从外部源到带有PCIe卡的Linux机箱.PCIe卡带有一些第三方驱动程序,它们使用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 );*/
Run Code Online (Sandbox Code Playgroud)
在申请中:
// 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
Run Code Online (Sandbox Code Playgroud)
另一个有趣的事情是,在完成所有这些之前,从dma_alloc_coherent返回的物理地址大于系统上的RAM量(0x83d000000).我认为在x86中RAM总是最低的地址,因此我希望地址小于32GB.
任何帮助,将不胜感激.
小智 1
不要通过 限制系统内存量mem
,而是尝试使用 CMA: https: //lwn.net/Articles/486301/
使用 CMA 内核命令行参数允许您为保证连续的 DMA 操作保留一定量的内存。内核将允许非 DMA 进程访问该内存,但一旦 DMA 操作需要该内存,非 DMA 进程就会被逐出。因此,我建议不要更改mem
参数,而是添加cma=4G
到命令行中。dma_alloc_coherent
应该自动从该保留空间中提取,但您可以在内核配置中启用 CMA 调试来确保。
归档时间: |
|
查看次数: |
1166 次 |
最近记录: |