什么是DMA和CPU访问内存的一致性问题
问题1:当CPU访问某一块内存A时,CPU访问的时候,如果cache没有命中,则会将A这块内存里 面的数据刷新到cache中,当CPU再次读取A内存的数据发现cache已经命中,直接在cache 中取数据即可,不必再去更新内存的数据。这个时候如果有一个DMA的操作,去操作了A这 块内存,但是CPU不知道这块内存的数据已经更新,当CPU再次读取A块内存的数据时,发 现cache命中了,还是会直接读取cache的数据,而不更新内存的数据,这个时候就造成了 cache和内存里面数据不一致的情况。
问题2:CPU写一片内存A,但是CPU写这块内存的时候,其实是先写在cache上,在适当的时候再 写回内存中。这个时候,我们想要写一些数据到内存,然后再通过DMA操作把这块数据搬 到设备FIFO上去,如果我们想要写的数据没有从cache中write back回内存,这个时候就会出现 我要给用户发送的数据和用户收到的数据不一致的问题。
上面两个问题会带来两个问题:一种是别人给我发数据,我读取到的数据不对。另一种是我要发给别人数据,我觉得我已经写到内存中,然后通过DMA发给了对方,但是对方读取的数据不对。
如何解决一致性问题
两种解决方法:
一致性DMA映射(Consistent DMA mappings )
CPU和DMA controller在发起对DMA buffer的并行访问的时候不需要考虑cache的影响,CPU和DMA controller都可以看到对方对DMA buffer的更新。
dma_alloc_coherent()
dma_alloc_writecombine()
dma_pool_alloc()
流式DMA映射(streaming DMA mapping)
这种方式在map的时候要指定一个参数,来指明数据的方向是从外设到内存还是从内存到外设:
从内存到外设:CPU会做cache的flush操作,将cache中新的数据刷到内存。
从外设到内存:CPU将cache置无效,这样CPU读的时候不命中,就会从内存去读新的数据。
map单个的dma buffer: dma_map_single()
map多个形成scatterlist的dma buffer: dma_map_sg()
下篇文章一起看下这两类接口的用法和实现。