我知道"magic ring buffer"技巧涉及镜像进程地址空间中的底层缓冲区,以允许数据块与单个memcpy()
一起排队,而不必担心环绕。
我想在Linux内核模块中完成同样的事情。假设我使用dma_alloc_coherent()
创建了一个缓冲区,其虚拟地址为V
,其长度为N
。如何创建映射,使其虚拟地址[V+N,V+2N)
映射到与[V,V+N)
相同的基础页面?
注意:这是在32位ARM Linux中。
答案 0 :(得分:0)
drivers/firewire/ohci.c将异步接收环缓冲区的某些页面映射两次,以便更容易地访问收到的包裹的数据包:
for (i = 0; i < AR_BUFFERS; i++) {
ctx->pages[i] = alloc_page(GFP_KERNEL | GFP_DMA32);
...
dma_addr = dma_map_page(ohci->card.device, ctx->pages[i],
0, PAGE_SIZE, DMA_FROM_DEVICE);
...
}
for (i = 0; i < AR_BUFFERS; i++)
pages[i] = ctx->pages[i];
for (i = 0; i < AR_WRAPAROUND_PAGES; i++)
pages[AR_BUFFERS + i] = ctx->pages[i];
ctx->buffer = vmap(pages, ARRAY_SIZE(pages), VM_MAP, PAGE_KERNEL);
...
据我所知,相干DMA内存没有类似的API。如果您知道架构如何处理此页面,则可以重新映射dma_alloc_coherent()
返回的页面。
请注意,如果您使用多个虚拟地址修改相同的物理地址,某些体系结构的缓存可能会出现问题。即使你设法映射它,你也必须检查一致的DMA存储器是否可以在你的特定拱门中缓存。