dma 和 cache的一致性( 二 )


void *dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp);void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr_t handle);
一般驱动使用多,申请一片 mem ,这样无需考虑data 一致性 。代码流程:对page ,也就是是页管理的页面属性设置成,在缺页异常填TLB时,该属性就会写到TLB的存储属性域中 。保证了映射的地址空间是的 。
首先对分配到的缓冲区进行cache刷新,之后将该缓冲区的页表修改为,以此来保证之后DMA与CPU操作该块数据的一致性 。
对于通常的硬件平台(不带硬件cache 一致性的组件), 内存操作,CPU 直接操作内存,没有cache 参与 。
但是也有例外,有的CPU 很强, 也是可以申请到 带 cache的内存的 。
2.流式DMA映射(DMA),
实际工程中,我们自己写的驱动,当然可以使用 申请一致性的内存,但是实际工程中,我们并不能使用, 我们很难控制内存是自己申请的,举个例子:
dma_addr_t dma_map_single(struct device *dev, void *cpu_addr, size_t size, enum dma_data_direction dir)void dma_unmap_single(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir)void dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir)void dma_sync_single_for_device(struct device *dev, dma_addr_t handle, size_t size, enum dma_data_direction dir)int dma_map_sg(struct device *, struct scatterlist *, int, enum dma_data_direction);void dma_unmap_sg(struct device *, struct scatterlist *, int, enum dma_data_direction);
相关接口为 (), (),(),() 。
一致性缓存的方式是内核专门申请好一块内存给DMA用 。而有时驱动并没这样做,而是让DMA引擎直接在上层传下来的内存里做事情 。
例如从协议栈里发下来的一个包,想通过网卡发送出去 。
但是协议栈并不知道这个包要往哪里走,因此分配内存的时候并没有特殊对待,这个包所在的内存通常都是可以cache的 。传过来的的并不是你申请的,而且不是 申请的一致性内存,这个时候你要把 的内容发出去,或者把收到的报文扔到这个 里面去,那这个时候怎么办呢?
这时,内存在给DMA使用之前,就要调用一次()或(),取决于你的DMA引擎是否支持聚集散列(DMA -),支持就用(),不支持就用() 。DMA用完之后要调用对应的unmap接口 。
由于协议栈下来的包的数据有可能还在cache里面,调用()后,CPU就会做一次cache的flush,将cache的数据刷到内存,这样DMA去读内存就读到新的数据了 。
dma_map_single (做一遍cache的flush ,将cache的内容flush到内存)dma 发报文 (由于做过flush ,发的就是正确的包)dma_unmap_single dma_map_single (做一遍cache的invalid,将cache的内容无效,重新读取内存)dma 发报文 (由于做过invalid ,收到的就是正确的包)dma_unmap_single dma_map_single 是有一个方向的参数的,来决定是invalid 还是 flush
注意,在map的时候要指定一个参数,来指明数据的方向是从外设到内存还是从内存到外设:
从内存到外设:CPU会做cache的flush操作,将cache中新的数据刷到内存 。
从外设到内存:CPU将cache置无效 ,这样CPU读的时候不命中,就会从内存去读新的数据 。
(CPU读取cache 都是自动硬件完成的,软件不能干预,但是可以控制cache,可以 可以 flush)
还要注意,这几个接口都是一次性的,每次操作数据都要调用一次map和unmap 。并且在map期间,CPU不能去操作这段内存,因此如果CPU去写,就又不一致了 。
同样的,()和()的后端实现也都是和硬件特性相关 。
其他方式
上面说的是常规DMA,有些SoC可以用硬件做CPU和外设的cache ,例如在SoC中集成了叫做“Cache”的硬件,它可以做到让DMA踏到CPU的cache或者帮忙做cache的刷新 。这样的话,()申请的内存就没必要是非cache的了 。