3

我将多个物理上不连续的内存缓冲区映射到单个线性用户空间地址。我使用 vm_insert_page() 和 get_page()。我需要在所有分配的页面上使用 get_page() 因为只有给定缓冲区的第一页的引用计数 > 0 并且 vm_insert_page() 需要引用计数 > 0。据说(根据网络上的一些帖子)我如果不再需要,必须通过调用 get_page() 来“释放”我增加引用计数的页面。但是,我不太确定如何“释放”这些页面。我是否需要跟踪 get_page() 返回的每个页面结构,然后在取消映射期间调用相应的 API 来释放页面?看起来操作系统不会自动为我做这件事。即用户进程存在后,

我的伪代码是这样的:

    使用调用 pci_alloc_consistent() 分配多个 phys 非连续内存缓冲区
    对于上面分配的所有缓冲区中的所有 4K 块
         使用 virt_to_page(phys_chunk_addr) 创建一个页面结构
         // 这是必需的,因为只有物理缓冲区的第一页
         // 引用计数 > 0,这是 vm_insert_page() 所需要的!
         通过调用 get_page() 增加页面引用计数
         使用 vm_insert_page() 将页面放入 vma
    
感谢您的任何建议/指示。担。

4

1 回答 1

1

DMA 相干内存可能需要特定于体系结构的缓存标志,因此您不能简单地将其映射到用户空间。

pci_alloc_consistent已弃用。要映射单个连续内存块,请使用dma_alloc_coherentdma_mmap_coherent


如果您不太关心可移植性,则可以避免dma_alloc_coherent完全使用并使用单个页面:

  • 分配一堆页面alloc_page(对于PCI,您通常需要GFP_DMA32);
  • 获取每个页面的 DMA 地址dma_map_page
  • 将它们映射到用户空间vm_insert_page

请注意,这不是连贯的 DMA 映射,而是流式 DMA 映射。在 x86 上,这无关紧要,但在许多其他架构上,您必须dma_sync_在适当的时候调用 * 函数。

有关内核中的示例,请参见drivers/firewire/core-iso.c, core-cdev.c


如果您需要将多个大型且物理上连续的缓冲区映射到一个几乎连续的区域,则不能使用dma_mmap_coherent,因此您必须以艰难的方式做到这一点:

  1. dma_alloc_coherent根据需要随时拨打电话;
  2. 在您的mmap实现中,只需设置vm_area_struct->vm_ops
  3. in vm_operations_struct.fault, call virt_to_page, call get_page, 并设置vm_fault->page到页面。

例如,请参阅sound/core/pcm_native.c

于 2013-07-19T13:27:20.653 回答