我知道"魔术环形缓冲区"技巧,它涉及在进程的地址空间中镜像底层缓冲区,以允许数据块通过单个memcpy()
进行排队,而不必担心换行。
我想在Linux内核模块中实现相同的功能。假设我使用dma_alloc_coherent()
创建了一个缓冲区,其虚拟地址为V
,长度为N
。如何创建映射,以便其虚拟地址[V+N,V+2N)
映射到与[V,V + N)
相同的底层页面?
注意:这是在32位ARM Linux下进行的。
我知道"魔术环形缓冲区"技巧,它涉及在进程的地址空间中镜像底层缓冲区,以允许数据块通过单个memcpy()
进行排队,而不必担心换行。
我想在Linux内核模块中实现相同的功能。假设我使用dma_alloc_coherent()
创建了一个缓冲区,其虚拟地址为V
,长度为N
。如何创建映射,以便其虚拟地址[V+N,V+2N)
映射到与[V,V + N)
相同的底层页面?
注意:这是在32位ARM Linux下进行的。
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_alloc_coherent()
返回的页面。