首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >大型PCIe DMALinuxx86-64

大型PCIe DMALinuxx86-64
EN

Stack Overflow用户
提问于 2015-11-20 09:28:56
回答 1查看 1.9K关注 0票数 9

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

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

由于这是一台一次性的实验机器,我认为最快/最简单的方法是使用mem=28GB引导配置参数。我可以很好地工作,但是从虚拟空间访问内存的下一步是我遇到问题的地方。下面是压缩成相关组件的代码:

在内核模块中:

代码语言:javascript
复制
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 );*/

在应用程序中:

代码语言:javascript
复制
// 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返回的物理地址大于系统上的内存量(0x83d000000)。我认为在x86中,内存将始终是最低的地址,因此我希望地址小于32 in。

任何帮助都将不胜感激。

EN

回答 1

Stack Overflow用户

发布于 2017-11-17 01:24:56

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

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33817481

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档