我试图直接从Linux中的另一个PCIe设备访问NIC中的DMA地址。 具体来说,我试图从NVIDIA GPU读取,以绕过所有的CPU。 我已经研究了零拷贝networking和DMA到用户空间的post,但是他们要么没有回答这个问题,要么涉及到从内核空间到用户空间的一些拷贝。 我试图避免使用任何CPU时钟,因为与延迟不一致,并且我有非常严格的延迟要求。
我拿到了我使用的intel卡(e1000e驱动程序)的NIC驱动程序,我发现在哪里分配了环形缓冲区。 正如我在前面的文章中所理解的那样,我会对dma_addr_ttypes的描述符感兴趣。 他们也有一个叫做dma的rx_ring结构体的成员。 我使用ioctl调用来传递desc和dma成员,但除了零之外,我无法在GPU中获得任何东西。
GPU代码如下:
int *setup_gpu_dma(u64 addr) { // Allocate GPU memory int *gpu_ptr; cudaMalloc((void **) &gpu_ptr, MEM_SIZE); // Allocate memory in user space to read the stuff back int *h_data; cudaMallocHost((void **)&h_data, MEM_SIZE); // Present FPGA memory to CUDA as CPU locked pages int error = cudaHostRegister((void **) &addr, MEM_SIZE, CU_MEMHOSTALLOC_DEVICEMAP); cout << "Allocation error = " << error << endl; // DMA from GPU memory to FPGA memory cudaMemcpy((void **) &gpu_ptr, (void **)&addr, MEM_SIZE, cudaMemcpyHostToDevice); cudaMemcpy((void **) &h_data, (void **)&gpu_ptr, MEM_SIZE, cudaMemcpyDeviceToHost); // Print the data // Clean up }
我究竟做错了什么?
cudaHostRegister()
在已经分配的主机内存上运行,所以你必须通过addr
,而不是&addr
。
如果addr
不是主机指针,这将不起作用。 如果它是一个主机指针,你的函数接口应该使用void *
,那么就不需要类型转换了。