Linux:如何将一系列物理连续区域误解到用户空间中



在我的驱动程序中,我有一定数量的物理连续的DMA缓冲区(例如每个MB长)从设备接收数据。它们使用SG列表通过硬件来处理。由于接收到的数据将经过密集处理,因此我不想关闭缓存,我将使用 dma_sync_single_for_for_for_for_for_for_for_for_cpu DMA填充每个缓冲区后。

为了简化数据处理,我希望这些缓冲区在用户空间中显示为一个巨大的,连续的圆形缓冲区。如果单个缓冲区,我只需使用 remap_pfn_range dma_mmap_coherent 。但是,我不能多次使用这些功能来映射连续的缓冲区。

当然,我可以在 vm_operations 中实现故障操作,并使用VM_INSERT_PFN将其插入VMA中。

收购将非常快,因此当真实数据到达时,我无法处理映射。但这可以很容易地解决。要在数据获取启动之前准备所有映射,我可以在开始采集之前只读取整个MMMAPPER BUFFER,以便在第一个数据到达时已经插入所有页面。

tha 故障的技巧应该起作用,但也许有更优雅的东西?只是一个单个功能,可以多次调用以逐步构建整个映射?

其他难度是该解决方案应适用(调整最少),从2.6.32到最新的内核。

ps。我已经看到那个烦人的帖子。是否存在危险的危险,如果该应用程序试图将一些内容写入Mmmapped Buffer(仅执行数据处理),我精心构建的映射将被Cow销毁?

下面是我的解决方案,用于分配给dmam_alloc_noncoherent的缓冲区。

缓冲区的分配:

[...]
for(i=0;i<DMA_NOFBUFS;i++) {
    ext->buf_addr[i] = dmam_alloc_noncoherent(&my_dev->dev, DMA_BUFLEN, &my_dev->buf_dma_t[i],GFP_USER);
    if(my_dev->buf_addr[i] == NULL) {
        res = -ENOMEM;
        goto err1;
    }
    //Make buffer ready for filling by the device
    dma_sync_single_range_for_device(&my_dev->dev, my_dev->buf_dma_t[i],0,DMA_BUFLEN,DMA_FROM_DEVICE);
}
[...]

缓冲区的映射

void swz_mmap_open(struct vm_area_struct *vma)
{
}
void swz_mmap_close(struct vm_area_struct *vma)
{
}
static int swz_mmap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
{
    long offset;
    char * buffer = NULL;
    int buf_num = 0;
    //Calculate the offset (according to info in https://lxr.missinglinkelectronics.com/linux+v2.6.32/drivers/gpu/drm/i915/i915_gem.c#L1195 it is better not ot use the vmf->pgoff )
    offset = (unsigned long)(vmf->virtual_address - vma->vm_start);
    buf_num = offset/DMA_BUFLEN;
    if(buf_num > DMA_NOFBUFS) {
        printk(KERN_ERR "Access outside the buffern");
        return -EFAULT;
    }
    offset = offset - buf_num * DMA_BUFLEN;
    buffer = my_dev->buf_addr[buf_num];
    vm_insert_pfn(vma,(unsigned long)(vmf->virtual_address),virt_to_phys(&buffer[offset]) >> PAGE_SHIFT);         
    return VM_FAULT_NOPAGE;
}
struct vm_operations_struct swz_mmap_vm_ops =
{
    .open =     swz_mmap_open,
    .close =    swz_mmap_close,
    .fault =    swz_mmap_fault,    
};
static int char_sgdma_wz_mmap(struct file *file, struct vm_area_struct *vma)
{
    vma->vm_ops = &swz_mmap_vm_ops;
    vma->vm_flags |= VM_IO | VM_RESERVED | VM_CAN_NONLINEAR | VM_PFNMAP;
    swz_mmap_open(vma);
    return 0;
}

最新更新