c++ - 大型 PCIe DMA Linux x86-64

标签 c++ linux redhat dma pci-e

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

这个系统有 32GB 内存,运行的是内核版本为 3.10 的 Red Hat,我想为连续的 DMA 提供 4GB 内存。我知道首选方法是分散/聚集,但在我的情况下这是不可能的,因为有一个硬件芯片将串行协议(protocol)转换为我无法控制的 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 调试以确保这一点。

关于c++ - 大型 PCIe DMA Linux x86-64,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33817481/

相关文章:

amazon-web-services - 如何通过 SSH 连接到 Redhat EC2 实例?

c++ - 为枚举参数化的模板

c++ - RPC:永不消亡的子进程

c - 需要帮助理解 C 程序以找到机器 IP 地址

linux - 如何让 systemd 变量在重启后仍然存在?

用于通过 rDesktop 测试 GUI 应用程序的 Linux 软件

java - 如何使用 jni 将数据从 java InputStream 移动到 C++ 中的 char *?

c++ - 嵌套 QDockWidgets

c++ - 如何在不终止应用程序的情况下关闭 GLUT 窗口?

python - os.system ('sudo shutdown now -P' ) 不适用于 cloud-init