1.一致性映射:关闭cache,但写缓冲可以在,使用方式:dma_alloc_writecombine 分配出来的内存不使用缓存cache,但是会使用写缓冲区。而 dma_alloc_coherent 则二者都不使用。;
2.流式映射:
在流式DMA映射场合,DMA传输通道所使用的缓冲区往往不是由当前驱动程序自身分配的,而且往往每次DMA传输都会重新建立一个流式映射的缓冲区。此外,由于无法确定外部模块传入的DMA缓冲区的映射情况,所以设备驱动程序必须小心地处理可能会出现的cache一致性问题。
(1)在向内传输(rx)时,DMA设备将数据写入内存后,DMAC将向CPU发出中断请求,在RX ISR中使用该内存之前,需要先InvalidateD-Cache(sync_single_for_cpu)使cache无效重填(refill),此时CPU通过高速缓存cache获得的才是最新的数据。
/* 确定中断是由对应的设备发来的*/
dma_unmap_single(dev->pci_dev->dev,dev->dma_addr,
dev->dma_size,dev->dma_dir);
/* 释放之后,才能访问缓冲区,把它拷贝给用户 */
(2)在向外传输(tx)时,一种可能的情形是CPU构造的本地协议栈反馈包还在D-Cache中,故在send调用中需要先Flush D-Cache(sync_single_for_device)将数据写回(write back)到内存,使DMA缓存更新为最新鲜的待发送数据再启动DMA TX trigger。
说白了就是接收清cache操作sync_single_for_cpu,发送刷cache操作sync_single_for_device。
CPU的读/写用的是不同的cache(读用的是cache,写则用的是write buffer),所以建立流式DMA映射需要指明数据在DMA通道中的流向,以便由内核决定是操作cache还是write buffer。
3.分散/聚集DMA映射(scatter/gather map)
到目前为止,对DMA操作时缓冲区的映射问题的讨论仅限于单个缓冲区,接下来将讨论另一种类型的DMA映射——分散/聚集映射。
分散/聚集映射通过将虚拟地址上分散的多个DMA缓冲区通过一个类型为struct scatterlist的数组或链表组织起来,然后通过一次的DMA传输操作在主存RAM和设备之间传输数据。可以类比WinSock中WSA系列API提供的Scatter/GatherI/O特性。
上图显示了主存中三个分散的物理页面与设备之间进行的一次DMA传输时分散/聚集映射示意。其中单个物理页面与设备之间可以看做是一个单一的流式映射,每个这样的单一映射在内核中有数据结构strcut scatterlist来表示。
如果从CPU的角度来看这种分散/聚集映射,它对应的需求时三块数据(分别存放在三段分散的虚拟地址空间中)需要和设备进行交互(发送或者接收),通过建立struct scatterlist类型的数组/链表在一次DMA传输中完成所有的数据传输。这样,通过减少重复的DMA传送请求来提高效率。
通过上面的讨论可知,分散/聚集映射本质上是通过一次DMA操作把主存中分散的数据块在主存与设备之间进行传输,对于其中的每个数据块内核都会建立对应的一个流式DMA映射。但是对于MIPS、ARM平台而言,还是需要通过软件来保证cache的一致性问题。