五 DMA及Cache一致性

整体目录

一 linux虚拟内存、MMU、分页的基本原理
二 OOM打分因子、oom_adj以及oom_score
三 页的alloc与free、Buddy算法以及CMA
四 page_fault、内存IO交互、VSS、LRU
五 DMA及Cache一致性

=================================================================================

cache的作用:

  • CPU在访问内存时,首先判断所要访问的内容是否在Cache中,如果在,就称为“命中(hit)”,此时CPU直接从Cache中调用该内容;否则,就称为“missing”,CPU只好去内存中调用所需的子程序或指令了。
  • CPU不但可以直接从Cache中读出内容,也可以直接往其中写入内容。
  • Cache的存取速率相当快,使得CPU的利用率大大提高,进而使整个系统的性能得以提升。
  • Cache的一致性就是直Cache中的数据,与对应的内存中的数据是一致的。

dma的作用:

  • DMA是直接操作总线地址的,这里先当作物理地址来看待(系统总线地址和物理地址只是观察内存的角度不同)。如果cache缓存的内存区域不包括DMA分配到的区域,那么就没有一致性的问题。但是如果cache缓存包括了DMA目的地址的话,一致性就会有问题,因为经过DMA操作,cache缓存对应的内存数据已经被修改了,而CPU本身不知道(DMA传输是不通过CPU的),它仍然认为cache中的数据就是内存中的数据,以后访问Cache映射的内存时,它仍然使用旧的Cache数据。这样就发生Cache与内存的数据“不一致性”错误。
    总线地址是从设备角度上看到的内存,物理地址是CPU的角度看到的未经过转换的内存(经过转换的是虚拟地址)

=============================================================

出现内存不一致的原因

CPU写内存的时候有两种方式:

  1. write through: CPU直接写内存,不经过cache。
  2. write back: CPU只写到cache中。cache的硬件使用LRU算法将cache里面的内容替换到内存。通常是这种方式。

DMA可以完成从内存到外设直接进行数据搬移。但DMA不能访问CPU的cache,CPU在读内存的时候,如果cache命中则只是在cache去读,而不是从内存读,写内存的时候,也可能实际上没有写到内存,而只是直接写到了cache。

这样一来,如果DMA从将数据从外设写到内存,CPU中cache中的数据(如果有的话)就是旧数据了,这时CPU在读内存的时候命中cache了,就是读到了旧数据;CPU写数据到内存时,如果只是先写到了cache,则内存里的数据就是旧数据了。这两种情况(两个方向)都存在cache一致性问题。例如,网卡发包的时候,CPU将数据写到cache,而网卡的DMA从内存里去读数据,就发送了错误的数据。
在这里插入图片描述

如何解决一致性问题

1.一致性DMA缓存(Coherent DMA buffers)

DMA需要的内存由内核去申请,内核可能需要对这段内存重新做一遍映射,特点是映射的时候标记这些页是不带cache的,这个特性也是存放在页表里面的。
上面说“可能”需要重新做映射,如果内核在highmem映射区申请内存并将这个地址通过vmap映射到vmalloc区域,则需要修改相应页表项并将页面设置为非cache的,而如果内核从lowmem申请内存,我们知道这部分是已经线性映射好了,因此不需要修改页表,只需修改相应页表项为非cache即可。
相关的接口就是dma_alloc_coherent()和dma_free_coherent()。dma_alloc_coherent()会传一个device结构体指明给哪个设备申请一致性DMA内存,它会产生两个地址,一个是给CPU看的,一个是给DMA看的。CPU需要通过返回的虚拟地址来访问这段内存,才是非cache的。至于dma_alloc_coherent()的内部实现可以不关注,它是和体系结构如何实现非cache(如mips的kseg1)相关,也可能与硬件特性(如是否支持CMA)相关。
因为内存是可cache的,因此在DMA读内存(内存到设备方向)时,由于cache中可能有新的数据,因此要先将cache中的数据写回到内存(writeback );在DMA写内存(设备到内存方向)时,cache中可能还有数据没有写回,为了防止cache数据覆盖DMA要写的内容,要先将cache无效(invalidate )。注意这个函数的vaddr参数接收的是虚拟地址。

2.流式DMA映射(DMA Streaming Mapping)

相关接口为
dma_map_sg(), dma_unmap_sg(),
dma_map_single(),dma_unmap_single()。
流式DMA映射实现比较复杂,生命周期比较短,而且禁用cache。一些硬件对流式映射有优化。建立流式DMA映射,需要告诉内核数据的流动方向; dma_alloc_writecombine

=============================================================

参考资料

具体可以查看该网址:Linux内存管理 —— DMA和一致性缓存

猜你喜欢

转载自blog.csdn.net/baidu_38410526/article/details/104111786
今日推荐