Linux内核空间中的“魔环缓冲”实现?

时间:2017-04-06 00:27:12

标签: c linux-kernel arm linux-device-driver circular-buffer

我知道"magic ring buffer"技巧涉及镜像进程地址空间中的底层缓冲区,以允许数据块与单个memcpy()一起排队,而不必担心环绕。

我想在Linux内核模块中完成同样的事情。假设我使用dma_alloc_coherent()创建了一个缓冲区,其虚拟地址为V,其长度为N。如何创建映射,使其虚拟地址[V+N,V+2N)映射到与[V,V+N)相同的基础页面?

  

注意:这是在32位ARM Linux中。

1 个答案:

答案 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存储器是否可以在你的特定拱门中缓存。