簡體   English   中英

將多個內核緩沖區映射到連續的用戶空間緩沖區?

[英]Map multiple kernel buffer into contiguous userspace buffer?

我使用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)\n", rc, idx);
            return -EAGAIN;
        }
    }
    
    /* Restore VMA addresses */
    vma->vm_start = vm_start_orig;
    vma->vm_end = vm_end_orig;
    
    return rc;
}

不幸的是,目前唯一支持 mmap()ing DMA 一致性內存的方法是宏dma_mmap_coherent()或函數dma_mmap_attrs() (由dma_mmap_coherent()調用)。 不幸的是,這不支持將單個 VMA 拆分為多個單獨分配的 DMA 相干內存塊。

(我希望有一種支持的方法可以將 VMA 的 mmap() 拆分為多個 DMA 相干內存分配,因為它會影響我幫助維護的內核子系統中的緩沖區分配。我不得不更改它以將緩沖區分配為一個單一的 DMA 一致性內存塊,而不是許多頁面大小的塊。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM