目录
4.2.2. scatterlist streaming DMA
4.2.2. streaming DMA sync cache
6.12 dmaengine_prep_dma_cyclic
6.13 dmaengine_prep_interleaved_dma
1. DMA子系统概述
DMA子系统为不同的DMA控制器提供统一的注册接口,为DMA使用者提供屏蔽DMA控制器实现细节的统一接口。
2. DMA子系统软件框架

DMA子系统由四大部分构成:
1. dmaengine: 实现DMA子系统的DMA设备注册,为DMA使用者提供屏蔽DMA控制器实现细节的统一接口。
2. virt-dma:为DMA子系统提供虚拟DMA channel的支持
3. of-dma:为DMA子系统提供DMA 设备树的支持
4. dma driver:为DMA控制器的实现
2.1 DMA子系统内部实现

以全志平台为例。
DMA内部主要数据结构已经流出如上图所示。
3. DMA 地址
CPU CPU Bus
Virtual Physical Address
Address Address Space
Space Space
+-------+ +------+ +------+
| | |MMIO | Offset | |
| | Virtual |Space | applied | |
C +-------+ --------> B +------+ ----------> +------+ A
| | mapping | | by host | |
+-----+ | | | | bridge | | +--------+
| | | | +------+ | | | |
| CPU | | | | RAM | | | | Device |
| | | | | | | | | |
+-----+ +-------+ +------+ +------+ +--------+
| | Virtual |Buffer| Mapping | |
X +-------+ --------> Y +------+ <---------- +------+ Z
| | mapping | RAM | by IOMMU
| | | |
| | | |
+-------+ +------+
DMA中会涉及到几类型的地址:
1. 虚拟地址:内核通常使用的地址就是虚拟地址,大部分是由kmalloc、vmalloc以及类似的接口申请并返回。
2. 物理地址:DRAM空间的地址
3. 总线地址:系统mapping出来的地址空间
如上图中
A-->B-->C的过程表示设备寄存器的访问过程
X-->Y-->Z的过程表示DMA访问设备FIFO的过程
在某些系统(U-boot)DMA直接访问物理地址,但是在许多系统,是通过 IOMMU来实现物理地址的转换(Z-->Y)。
例如:通过提供虚拟地址X给dma_map_single(),dma_map_single()通过该IOMMU映射以及返回DMA 可以访问的总线地址Z,以及IOMMU映射Z到Y(系统RAM,例如DRAM空间地址)
Tips:
-
1). 在Linux系统中虚拟地址通常存储在void *,物理地址通常存储在phys_addr_t或者resource_size_t。
2). 在某些平台上总线地址=物理地址,但通常不这么做,IOMMUs和主机网桥可以在物理地址和总线地址之间生成任意映射
3). 总线地址A通过内部桥转换为CPU物理地址B,Ioremap()实现物理地址B到虚拟地址C的映射,然后可以ioread32(C)来访问总线地址A
4).DMA地址应该使用dma_addr_t类型
4. DMA类型
这里说的DMA类型是从DMA地址的角度出发的,分为两类:
1. Coherent(consistent) DMA(一致性DMA)
2. Streaming DMA(流式DMA)
4.1. Coherent DMA
Coherent DMA在访问DDR的时候不经过cpu cache。
Coherent DMA确保设备和CPU可以并行访问数据,并在不进行任何显式软件刷新的情况下看到彼此进行的更新。
Tips:
- 1). 通常在驱动初始化时候map,在卸载或者结束的时候unmap
- 2). 如果要确保设备按顺序看到你的配置可以使用内存屏障来保证内存排序:
- e.g.
-
desc->word0 = address; wmb(); desc->word1 = DESC_VALID;3). 在某些平台上,驱动程序可能需要刷新CPU写缓冲区(跟CPU架构有关,ARM cortex_a53 没有write buffer, ARMv9有write buffer),其方式与刷新PCI桥中的写缓冲区的方式大致相同
-
4.1.1 Coherent DMA使用
- 1). 如果申请和映射的Coherent DMA域大于PAGE_SIZE(e.g. 4KB)使用如下接口:
-
dma_alloc_coherent。
-
e.g.
-
/*a. alloc coherent */ dma_addr_t dma_handle; cpu_addr = dma_alloc_coherent(dev, size, &dma_handle, gfp); @cpu_addr:CPU角度访问的虚拟地址,按PAGE_SIZE对齐,意味着大于等于申请大小 @dma_handle: DMA角度访问的物理地址,按PAGE_SIZE对齐,意味着大于等于申请大小 /*b. free coherent*/ dma_free_coherent(dev, size, cpu_addr, dma_handle);注意:
-
alloc出来的coherent dma域按PAGE_SIZE对齐。
-
2). 如果申请和映射的Coherent DMA域小于PAGE_SIZE(e.g. 4KB)使用如下接口:
-
/*dma pool*/ /*a.Create a dma_pool*/ struct dma_pool *pool = dma_pool_create(name, dev, size, align, boundary); @size:必须对齐2 /*b.Allocate memory from a DMA pool*/ cpu_addr = dma_pool_alloc(pool, flags, &dma_handle) @ flag:GFP_KERNEL /*c.Free memory*/ dma_pool_free(pool, cpu_addr, dma_handle); /*Destroy a dma_pool*/ dma_pool_destroy(pool) 调用之前先释放所有在dma pool中申请的内存
-
-
4.2. Streaming DMA
-
Streaming DMA在访问DDR的时候经cpu 过cache。
-
Streaming DMA流式DMA通常在某一次的传输中使用,使用之后取消。
-
4.2.1. Streaming DMA使用
有两类型的streaming DMA映射:single、scatterlist
1). Single streaming DMA
不使用HIGHMEM:
/*a. map a single region*/
dma_handle = dma_map_single(dev, addr, size, direction)
@dma_handle:DMA操作的物理地址
@addr:需要map的虚拟地址
/*b. unmap, DMA传输结束调用*/
dma_unmap_single(dev, dma_handle, size, direction);

本文深入介绍了DMA子系统,包括其软件框架、内存地址类型、Coherent DMA与Streaming DMA的使用、DMA地址转换以及DMA API的详细使用。内容涵盖了dma_alloc_coherent、dma_pool、dma_map_single等关键接口,并解释了DMA方向和DMAengine的使用流程。
最低0.47元/天 解锁文章
574

被折叠的 条评论
为什么被折叠?



