linux dma_alloc_coherent cache一致性问题
1. 问题背景
想提升vpu编解码帧率,在vpu的设备树节点添加dma-coherent属性,vpu编解码timeout(失败);
2. 所做尝试
2.1 vpu内存分配接口
b->virt = dma_alloc_coherent(dev, PAGE_ALIGN(size), &b->dma, GFP_DMA | GFP_KERNEL
2.2 分析
- 增加了dma-coherent属性之后,vpu编解码失败;
- vpu是一个与DDR强交互的ip(从ddr中取数据进行编解码,将编解码成功的数据返回给ddr)
所以进而考虑到可能是cache 一致性问题;
2.3 尝试
增加刷cache接口
vpu获取ddr数据
将cpu中的数据刷到ddr中:
vb2_ops->buf_queue: dma_sync_single_for_device(flush cache:刷写cache中内容到内存。即flush cache)
vpu返回数据给ddr
vb2_ops->buf_finish:dma_sync_single_for_cpu(invalid cache:从内存更新数据到cache,即invalid cache中的内容)
结果
vpu 编解码任然失败,
3. 学习dma cache一致性知识
参考:https://blog.csdn.net/juS3Ve/article/details/79135998
DMA ZONE
产生背景
-
DMA可以直接在内存和外设之间进行数据搬移,对于内存的存取来讲,它和CPU一样,是一个访问master,可以直接访问内存。
-
DMA ZONE产生的本质原因是:不一定所有的DMA都可以访问到所有的内存,这本质上是硬件的设计限制。所以我们划分一个zone,保证这个范围的内存是dma硬件绝对可以访问到的。
根据本质原理,我们可以了解,DMA ZONE的大小是取决于dma硬件的寻址能力的,这个区域要不要,要的话范围是多少,根据dma的寻址能力判断。
DMA ZONE的内存只能做DMA吗?
DMA ZONE的内存做什么都可以。DMA ZONE的作用是让有缺陷的DMA对应的外设驱动申请DMA buffer的时候从这个区域申请而已,但是它不是专有的。其他所有人的内存(包括应用程序和内核)也可以来自这个区域。
dma_alloc_coherent()申请的内存来自DMA ZONE?
dma_alloc_coherent()申请的内存来自于哪里,不是因为它的名字前面带了个dma_就来自DMA ZONE的,本质上取决于对应的DMA硬件是谁。
if (mask < 0xffffffffULL)
gfp |= GFP_DMA;
(这段代码存在arm架构,arm64已经不存在了)
dma_alloc_coherent()申请的内存是非cache的吗?
-
缺省情况下,dma_alloc_coherent()申请的内存缺省是进行uncache配置的。
-
也可以带cache
If the machine sets arm_coherent_dma_ops rather than arm_dma_ops, the memory will be cacheable,
- 那我们什么时候选择带cache的分配方式呢?当可以用硬件做CPU和外设的cache coherence时候。(硬件自动同步cache)
- 怎么选择这种分配方式呢?猜测是使用dma-coherent属性;
4. 最终解决
vpu获取ddr数据
将cpu中的数据刷到ddr中:
vb2_ops->buf_queue:arch_flush_dcache(flush cache:刷写cache中内容到内存。即flush cache)
vpu返回数据给ddr
vb2_ops->buf_finish:arch_invalidate_dcache(invalid cache:从内存更新数据到cache,即invalid cache中的内容)
为什么dma_sync_single_for_cpu/device不行
因为当有coherent属性的时候,这时候分配的内存带有cache了(没有coherent属性默认地址是不带cache的);而且系统会默认咱们硬件会处理cache一致性;
使用dma_sync_single_for_cpu/device时候,由于系统默认咱们处理了cache一致性,此时这两个函数并没有真正去刷cache,所以出现了问题;
TODO
- dma_sync_single_for_cpu/device代码分析。重点在带有coherent,和不带coherent属性时,刷cache的操作;
- dma_alloc_cohenrent接口分析。重点在带有coherent,和不带coherent属性时,内存cache分析;
- 感觉dma_alloc_coherent接口其实就是一个内存分配接口,没有看见和DMA的联系;那它到底和DMA 是否有联系呢?看代码时着重这个点分析;