我已经使用分配了多个内核可访问的缓冲区dma_alloc_coherent
,每个大小为 4MiB。目标是将这些缓冲区映射到连续的用户空间虚拟内存中。问题是remap_pfn_range
似乎不起作用,因为用户空间内存有时工作,有时不工作,或者有时复制缓冲区的页面映射。
// in probe() function
dma_alloc_coherent(&pcie->dev, BUF_SIZE, &bus_addr0, GFP_KERNEL);
dma_alloc_coherent(&pcie->dev, BUF_SIZE, &bus_addr1, GFP_KERNEL);
// ...
// in mmap() function
vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
pfn = dma_to_phys(&pcie->dev, &bus_addr0) >> PAGE_SHIFT;
remap_pfn_range(pfn, vma->vm_start + 0, pfn, BUF_SIZE, vma->vm_page_prot);
pfn = dma_to_phys(&pcie->dev, &bus_addr1) >> PAGE_SHIFT;
remap_pfn_range(pfn, vma->vm_start + BUF_SIZE, pfn, BUF_SIZE, vma->vm_page_prot);
我不太确定将多个内核缓冲区映射到连续用户空间内存的最佳方法,但我感觉我做错了。提前致谢。
我不知道为什么没有更好的接口来将多个缓冲区连续映射到用户空间。理论上你可以使用多次调用remap_pfn_range()
但获得正确的 pfn 分配的内存dma_alloc_coherent()
在某些平台(例如 ARM)上基本上是不可能的。
我针对这个问题提出了一个解决方案,该解决方案可能不被认为是“好的”,但在我在多个平台(x86_64 和各种 ARM)上的使用中似乎工作得足够好。解决办法是暂时修改一下起始地址和结束地址struct vm_area_struct
打电话时dma_mmap_coherent()
多次,每个缓冲区一次。只要将 VMA 开始和结束地址重置为其原始值,一切似乎都可以正常工作(请参阅我之前的免责声明)。
这是一个例子:
static int mmap(struct file *file, struct vm_area_struct *vma)
{
. . .
int rc;
unsigned long vm_start_orig = vma->vm_start;
unsigned long vm_end_orig = vma->vm_end;
for (int idx = 0; idx < buffer_list_size; idx++) {
buffer_entry = &buffer_list[idx];
/* Temporarily modify VMA start and end addresses */
if (idx > 0) {
vma->vm_start = vma->vm_end;
}
vma->vm_end = vma->vm_start + buffer_entry->size;
rc = dma_mmap_coherent(dev, vma,
buffer_entry->virt_address,
buffer_entry->phys_addr,
buffer_entry->size);
if (rc != 0) {
pr_err("dma_mmap_coherent: %d (IDX = %d)\n", rc, idx);
return -EAGAIN;
}
}
/* Restore VMA addresses */
vma->vm_start = vm_start_orig;
vma->vm_end = vm_end_orig;
return rc;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)