首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >是否每个dma_map_single调用都需要相应的dma_unmap_single?

是否每个dma_map_single调用都需要相应的dma_unmap_single?
EN

Stack Overflow用户
提问于 2013-04-23 22:34:50
回答 3查看 4.7K关注 0票数 5

我正在将一个大的代码库移植到Linux内核设备驱动程序。ASIC使用大量的DMA通道。

我用GFP_KERNEL|GFP_DMA实现了kmalloc内存。在启动DMA之前,我使用dma_map_single获取硬件(物理)内存地址,将其提供给硬件。(还会刷新/无效dcache中的内存吗?)在DMA完成后,我有时需要CPU访问数据,但并不经常。在我通过代码访问数据之前,我做了一个dma_unmap_single来避免缓存一致性问题。

在我不需要CPU访问的情况下,我还需要调用dma_unmap_single吗?我应该对我dma_map_single的每个指针执行dma_unmap_single操作吗?dma_map_single是否消耗dma_unmap_single将释放的资源(例如,表项)?

DMA-API.txt对于良好的DMA内存卫生不是很清楚。

谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-04-24 05:57:59

使用dma_map_single,您可以映射用于DMA传输的内存。您将获得指向内存的物理指针,因此设备可以DMA到该地址。

使用dma_unmap_single可以取消上面映射的内存的映射。您应该在传输结束后执行此操作。

您可以映射一个内存区域,并将其用于多个DMA传输,然后在作业完成时取消映射。每次想要访问DMA内存时,都必须对其进行同步。如果设备要访问内存,则应执行dma_sync_single_for_device;如果主机要访问内存,则应执行dma_sync_single_for_cpu

票数 5
EN

Stack Overflow用户

发布于 2017-10-04 08:07:21

dma_map接口可能会分配反弹缓冲区,在这种情况下,您需要调用dma_unmap函数。

票数 0
EN

Stack Overflow用户

发布于 2020-10-16 21:33:46

简短回答:

是。您应该使用dma_map_single对每个已映射的缓冲区执行dma_unmap_single

长篇答案:

当然也是。

您应该在每个DMA事务结束时调用dma_unmap_single

但是由于dma_map_single / dma_unmap_single是一个开销很大的操作,有时我们可能更喜欢(当数据包不太大的时候)重用DMA映射的缓冲区,所以我们不是在DMA事务结束时调用dma_unmap_single,而是调用dma_sync_single_for_cpu,然后将数据从DMA映射的缓冲区复制到其他缓冲区中,然后调用dma_sync_single_for_device,所以现在我们可以重用已经映射的缓冲区,而不需要在下一个DMA事务之前取消映射和重新映射它。

我猜测数据包在不同架构之间有多大,应该进行测量的阈值。

代码语言:javascript
复制
measure_time(dma_sync_single_for_cpu + memcpy(packet_size) + dma_sync_single_for_device) 
>?<
measure_time(dma_unmap_single + dma_map_single)

简短示例:

代码语言:javascript
复制
    if (frame_len < FRAME_LEN_THRESHOLD) {            
        skb = netdev_alloc_skb_ip_align(priv->dev, frame_len);
        if (unlikely(!skb)) {
            printk("packet dropped\n");
            continue;
        }
        
        dma_sync_single_for_cpu(priv->device, rx_skbuff_dma[entry],                                   
                                frame_len, DMA_FROM_DEVICE);

        // same as memcpy
        skb_copy_to_linear_data(skb, rx_skbuff[entry]->data, frame_len);

        dma_sync_single_for_device(priv->device, rx_skbuff_dma[entry],
                                   frame_len, DMA_FROM_DEVICE);

        /* now we can reuse rx_skbuff_dma[entry]. 
           no need to call dma_unmap_single */                           
    } else {
        skb = rx_skbuff[entry];
        if (unlikely(!skb)) {
            printk("packet dropped\n");
            continue;
        }

        rx_skbuff[entry] = NULL;

        dma_unmap_single(priv->device, rx_skbuff_dma[entry],
                         priv->dma_buffer_size, DMA_FROM_DEVICE);

        /* if we want to use rx_skbuff_dma[entry] for another DMA transaction, 
           we will need to realocate a buffer and call dma_map_single */                 
    }
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/16172118

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档