搞idm(internal DMA)模块时,看到数据从主芯片传输到WiFi芯片之前,会有一个idm_invalid_cache的动作,该函数里封装着dma_cache_maint
,这也就是我们平时经常说的刷cache,那这个内核函数作用是怎么样的呢?从以下几点展开说下:
1、为什么做缓存cache
我们都知道CPU的运算速度远高于内存的读写速度,CPU如果直接去操作DDR,会使得CPU花费很长时间等待数据到来,或者把数据写入内存。
这时就引入了cache,CPU缓存(Cache Memory)是位于CPU与内存之间的临时存储器,它的容量比内存小的多但是交换速度却比内存要快得多。
缓存中存放着内存中很小一部分的数据,但这一小部分是短时间内CPU即将访问使用的;如果CPU调用大量数据,就可避开内存直接从缓存中调用,从而加快读取速度。
2、cache一致性的问题
也正是由于缓存存在于CPU与内存中间,使得外设对内存的修改并不能保证cache中也得到同样的更新,同样的CPU对缓存中内容的修改也不能保证内存中的数据得到更新。
这种与DDR中的数据和cache中数据的不同步和不一致现象就是引入cache带来的一致性问题,最终可能导致使传输数据时或CPU运行改代码时产生出错。
3、DMA与cache
DMA(Direct Memory Access,直接存储器访问),将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。(DMA更多原理自行研究学习)
在进行DMA 操作时,如果没有对Cache 进行适当的操作,将可能产生以下两种错误:
-
1.DMA 从外设读取数据到供CPU使用。DMA 将外部数据直接传到内存中,但cache 中仍然保留的是旧数据,这样处理器在访问数据时直接访问缓存将得到错误的数据。
-
2.DMA 向外设写入由CPU提供的数据。处理器在处理数据时数据会先存放到cache 中,此时cache 中的数据有可能还没来得及写回到内存中的数据。如果这时DMA 直接从内存中取出数据传送到外设,外设将可能得到错误的数据。
为了正确进行DMA 传输,必须要对cache进行操作。 cache 操作主要分为 invalidate (作废) 和 writeback (写回) ,有时也将两着放在一起使用。
linux内核DMA 操作的函数如下:
- 路径:linux/arch/arm/mm/dma-mapping.c
- 源码:
/*
* Make an area consistent for devices.
* Note: Drivers should NOT use this function directly, as it will break
* platforms with CONFIG_DMABOUNCE.
* Use the driver DMA support - see dma-mapping.h (dma_sync_*)
*/
void dma_cache_maint(const void *start, size_t size, int direction)
{
void (*inner_op)(const void *, size_t ,int);
void (*outer_op)(unsigned long, unsigned long);
BUG_ON(!virt_addr_valid(start) || !virt_addr_valid(start + size - 1));
switch (direction) {
case DMA_FROM_DEVICE: /* invalidate only */
inner_op = dmac_map_area;
outer_op = outer_inv_range;
break;
case DMA_TO_DEVICE: /* writeback only */
inner_op = dmac_map_area;//dmac_unmap_area;
outer_op = outer_clean_range;
break;
case DMA_BIDIRECTIONAL: /* writeback and invalidate */
inner_op = dmac_flush_range;
outer_op = outer_flush_range;
break;
default:
BUG();
}
inner_op(start, size,direction);
outer_op(__pa(start), __pa(start) + size);
}
EXPORT_SYMBOL(dma_cache_maint);
direction有三种情况,一是DMA从外设中读取数据,二是将数据送入外设,还有就是外设和CPU交互数据。
-
1.DMA 从外设读取数据到供CPU使用时,使用invalidate 操作。这样将迫使CPU在读取cache中的数据时,先将数据从内存读取数据到缓存,保证缓存和内存中数据的一致性。
-
2.DMA 向外设写入由CPU传输的数据时,进行writeback 操作。这样可以DMA传输数据之前先将缓存中的数据写回到内存中。
-
3.我们在不清楚DMA 操作的方向时,也可先同时进行invalidate 和writeback 操作。操作的结果等同于invalidate 和 writeback 操作效果的叠加。
使用dma_cache_maint刷新cache之后,再对数据进行传输处理,这样便不会出错。