dma 和 cache的一致性

在介绍 cache 一致性之前,先明确一些概念~
1、之前谈到内存空间的时候,我们知道内存空间包括 内存 和 寄存器空间 。
2、CPU 、cache、内存、外设 之间的关系 。以及cache 一致性 是如何导致的
CPU写内存的时候有两种方式:
1. write : CPU直接写内存,不经过cache 。
2. write back: CPU只写到cache中 。cache的硬件使用LRU算法将cache里面的内容替换到内存 。通常是这种方式 。
我们假设MEM里面有一块红色的区域,并且CPU读过它,于是红色区域也进CACHE:
但是,假设现在DMA把外设的一个白色搬移到了内存原本红色的位置:
这个时候,内存虽然白了,CPU读到的却还是红色,因为CACHE命中了,这就出现了cache的不 。
当然,如果是CPU写数据到内存,它也只是先写进cache(不一定进了内存),这个时候如果做一个内存到外设的DMA操作,外设可能就得到错误的内存里面的老数据 。
所以cache 的最简单方法,自然是让CPU访问DMA 的时候也不带cache 。事实上,缺省情况下,()申请的内存缺省是进行配置的 。
但是,由于现代SoC特别强,这样有一些SoC里面可以用硬件做CPU和外设的cache ,如图中的cache:
这些SoC的厂商就可以把内核的通用实现掉,变成()申请的内存也是可以带cache的 。这部分还是让大牛Arnd 童鞋来解释:
来自:
Arnd :
() is aa - ,
based on the. The
fromgives you ,. It is
that theuses a(which isby readl/
but not / or /)
tothe writeare .
If thesetsthan ,
thewill be , as it'sthat the
is set up for cache- DMAs.
当我grep内核源代码的时候,我发现部分SoC确实是这样实现的:
所以 ()申请的内存 也是可以带cache的,这个要看硬件的,看厂商的,不过一般默认是不带cache的 。
所以要解决cache的不一致性 一般有三种方法 。
1、一种是硬件方案,例如上面介绍的在SoC中集成了叫做“Cache”的硬件,它可以做到让DMA踏到CPU的cache或者帮忙做cache的刷新 。这样的话,()申请的内存就没必要是非cache的了 。
2、一种是软件上禁用 cache ( 机制 ------ 一致性映射)
3、一种是DMA( 机制 ------ 流式映射)
下面主要介绍一下后面两种情况~
工程中一般有两种情况,会导致 cache的不一致性,不过都有对应的机制 。
(1)操作寄存器地址空间 。
寄存器是CPU与外设交流的接口,有些状态寄存器是由外设根据自身状态进行改变,这个操作对CPU是不透明的 。有可能这次CPU读入该状态寄存器,下次再读时,该状态寄存器已经变了,但是CPU还是读取的cache中缓存的值 。但是寄存器操作在中是必须保证一致的,这是控制外设的基础,IO空间通过进行映射到内核空间 。在映射寄存器地址时页表是配置为的 。数据不走cache,直接由地址空间中读取 。保证了数据一致性 。
这种情况已经保证了data的一致性,应用场景简单 。
(2)DMA申请的内存空间 。
DMA操作对于CPU来说也是不透明的,DMA导致内存中数据更新,对于CPU来说是完全不可见的 。反之亦然,CPU写入数据到DMA缓冲区,其实是写到了cache,这时启动DMA,操作DDR中的数据并不是CPU真正想要操作的 。
这种情况是,CPU 和DMA 都可以异步的对mem 进行操作,导致data不一致性 。
对于cpu 和 dma 都能访问的mem ,有专业的管理方式,分为两种:
1. 给DMA申请的内存,禁用 cache ,当然这个是最简单的,不过性能方面是有影响的 。
2. 使用过程中,通过flush cache /cache 来保证data 一致性 。
通用DMA层主要分为2种类型的DMA映射:
(1)一致性映射,代表函数: