将多个内核缓冲区映射到连续的用户空间缓冲区? [英] Map multiple kernel buffer into contiguous userspace buffer?

查看:18
本文介绍了将多个内核缓冲区映射到连续的用户空间缓冲区?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用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()使用多个调用,但在某些平台(例如ARM)上,为dma_alloc_coherent()分配的内存获取正确的PFN基本上是不可能的。

我已经想出了这个问题的解决方案,它可能不被认为是好的,但在我在多个平台(x86_64和各种ARM)上的使用中似乎工作得足够好。解决方案是在多次调用dma_mmap_coherent()时临时修改struct vm_area_struct中的起始地址和结束地址,每个缓冲区调用一次。只要将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)
", rc, idx);
            return -EAGAIN;
        }
    }
    
    /* Restore VMA addresses */
    vma->vm_start = vm_start_orig;
    vma->vm_end = vm_end_orig;
    
    return rc;
}

这篇关于将多个内核缓冲区映射到连续的用户空间缓冲区?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆