直接DMA直接存储到用户内存时刷新缓存

时间:2019-12-08 05:14:32

标签: caching linux-device-driver virtual-memory

我已经编写了一个驱动程序,其目的是允许用户空间程序固定其页面并获取页面的物理地址。

具体来说,我是通过在内核模块中调用get_user_pages_fast来实现的。

作为参考,可以在以下位置找到此模块的源代码:https://github.com/UofT-HPRC/mpsoc_drivers/tree/master/pinner

使用/dev/mem(是的,我的内核确实允许不安全的/dev/mem访问),我已经确认物理地址是正确的。

但是,我有一些外部硬件(准确地说是FPGA中的AXI DMA)无法正常工作,看来这可能是缓存一致性问题。在上面链接的代码的329-337行中,我这样做:(在此代码中,cm.usr_buf是用户虚拟地址)

//Find the VMA containing the user's buffer
struct vm_area_struct *vma = find_vma(current->mm, (unsigned long)cmd.usr_buf);
if (!vma) {
    printk(KERN_ALERT "pinner: unrecognized user virtual address\n");
    return -EINVAL;
}
flush_cache_range(vma, (unsigned long) cmd.usr_buf, (unsigned long) cmd.usr_buf + cmd.usr_buf_sz);

这似乎没有帮助。我还尝试了更通用的flush_cache_mm函数。

是否存在刷新用户页面缓存的正确方法?

1 个答案:

答案 0 :(得分:1)

我尝试了其他API来刷新缓存。洛朗·平查德(Laurent Pinchard)发表了一个名为“ Mastering the DMA and IOMMU APIs”的演讲,他在讲话中解释说,不应使用<asm/cacheflush.h>中的函数。而是在固定用户内存时可以使用dma_map_sgdma_unmap_sg之类的东西。我快速浏览了内核源代码,这些功能最终调用了特定于每种体系结构的汇编例程,这些例程可能负责禁用某些内存区域中的缓存。

此外,如果您尝试在DMA传输之间访问内存,则可以使用dma_sync_sg_for_cpudma_sync_sg_for_device强制进行高速缓存刷新。

我重写了内核驱动程序以使用这些功能,并且它起作用了。