由于cpu cache的影响,设备在进行DMA操作时存在数据一致性的问题,kernel实现了一系列 api来解决dma一致性问题:
include/linux/dma-mapping.h
dma_alloc_coherent/dma_free_coherent:一致性DMA缓冲区申请和释放
dma_map_single/dma_unmap_single:流式DMA映射
dma_map_sg/dma_unmap_sg:聚集/分散式DMA映射
从代码来看,这几个接口都是调用了dma_map_ops中对应的hook函数。dma_map_ops中的函数又是从哪来的呢?
我们知道,SoC上具有DMA功能的设备一般是外设的host,对于驱动来说就是platform_device,顺着of_platform_populate函数,可以找到arch_setup_dma_ops:
可见这里的主角是swiotlb_dma_ops:
__dma_alloc申请page_size倍数大小的连续物理内存,并将页表属性设置为MT_NORMAL_NC,通过禁用cache来保证一致性。
__swiotlb_map_page首先判断缓冲区是否在设备dma支持的地址范围之内,如果不是做一次回弹bounce,然后对cache做clean或invalid操作来同步cache与缓冲区的数据,保证数据一致性
__swiotlb_map_sg_attrs同上。
dma_alloc_coherent申请的是page_size倍数大小的内存,如果需要的dma缓冲区比较小,岂不是会造成浪费?kernel还有dma pool:
dma_pool_create/dma_pool_destroy:创建和销毁dma pool
dma_pool_alloc/dma_pool_free:从dma pool申请释放缓冲区
dma pool是通过将dma_alloc_coherent申请的大块的一致性映射缓冲区切分成小块来满足小块一致性dma缓冲区分配的需求,具体实现参考代码。