DMA--直接内存访问,硬件提供的机制,允许外设和主存之间直接传输数据,不需要CPU参与。
可大大提高外设的吞吐量,节省CPU开销。
两种方式:
1、软件read,基本过程如下:
1)进程调用read,驱动分配DMA缓冲区
2)驱动写DMA相关寄存器,通知硬件将数据写入DMA缓冲区
3)硬件将数据写入后,产生中断
4)中断处理程序处理中断,wakeup进程
5)进程read数据
2、异步方式,基本过程如下:
1)硬件产生中断,通知有新数据到来。
2)ISR分配DMA缓冲区
3)外设通过DMA,将数据写入缓冲区,并再次产生中断
4)ISR分发数据,wakeup相关进程
5)进程处理数据。
DMA缓冲区分配
1、通常需要连续的物理内存页(除非有特殊的硬件支持,比如IOMMU)
2、通常使用GFP_DMA标记在DMA区分配
3、通常的设备使用32位地址,只能寻址4G的空间。如果需要DMA使用4G以上的空间,通常需要使用bounce buffer,即在4G的地址空间范围内创建一个回弹缓冲区,通过该缓冲区来进行数据中转。但效率很低。
4、分配方法:
1)可以使用get_free_pages等方法手工分配
2)通过mem=参数,内核参数保留内存。
3)如果需要一大块内存,如果设备支持分散/聚集IO,则可将缓冲区分成小块。
4)标准方法,建议使用通用DMA层提供的接口,比如:dma_alloc_coherent(一致性映射)、dma_poot_create(dma池)、dma_map_single(流式映射)
总线地址
外设(PCI设备)使用的是总线地址,对于PCI设备来说,就是PCI总线域地址,而CPU使用的是CPU域地址(即通常说的物理地址),对于通常的x86机器来说,通常总线地址==物理地址,但其他平台来说,不一定,有时接口总线是通过将IO地址映射到不同的物理地址的桥接电路来连接。有些硬件平台甚至可以将任意页面在外围总线上表现为连续(比如IOMMU)。
virt_to_bus接口实现转换,但不通用,不建议使用个,只能实现简单的转换,对于有IOMMU或回弹缓冲区的情况不适用。建议使用通用DMA层的接口。
dma_addr_t结构表
通用DMA层
分配缓冲区,会将“总线地址”传给设备,为适应所有的硬件平台,引入了通用DMA层,与体系架构无关。提供一组标准的接口,对上层隐藏硬件细节。
DMA映射
一致性DMA映射:存在于驱动程序的生命周期中,缓冲区可同时被CPU和外设访问。必须保存在一致性缓存中,开销很大。通常不用
dma_alloc_coherent()
DMA池:
dma_pool_alloc
流式DMA映射:优化性能,访问规则更加严格。分配使用完成后,立刻释放,下次使用时再重新分配。
dma_map_single
有传送方向的限制,一旦缓冲区被映射,将属于设备,CPU不能访问,只有在unmap后CPU才能访问。
返回的就是总线地址。
DMA使用
1、映射缓冲区(提供的buffer是虚拟地址),对于网卡来说可以直接将skb->data映射到DMA缓冲区,减少一次skb拷贝。
2、将得到的总线地址写入DMA相关的寄存器中即可
阅读(3787) | 评论(0) | 转发(0) |