DMA

Scatter-gather DMA方式是与blockDMA方式相对应的一种DMA方式。

    DMA传输数据的过程中,要求源物理地址和目标物理地址必须是连续的。但是在某些计算机体系中,如IA架构,连续的存储器地址在物理上不一定是连续的,所以DMA传输要分成多次完成。


 

    如果在传输完一块物理上连续的数据后引起一次中断,然后再由主机进行下一块物理上连续的数据传输,那么这种方式就为blockDMA方式。Scatter-gather DMA方式则不同,它使用一个链表描述物理上不连续的存储空间,然后把链表首地址告诉DMA masterDMA master在传输完一块物理连续的数据后,不用发起中断,而是根据链表来传输下一块物理上连续的数据,直到传输完毕后再发起一次中断。


 

    很显然,scatter-gather DMA方式比blockDMA方式效率高。

 

 

 

总线主控DMA

DMA都是主控总线的,这里的总线主控DMA是指设备本身具备DMA功能,而无需使用系统DMA控制器。

总线主控DMA的设备,有两种基本的DMA方式

  • 基于包的DMA传输
  • 使用公共缓冲区的传输

基于包的DMA传输一般是这样的过程:

  1. IRP到达Dispacher
  2. Dispacher分配一个通道AllocateAdapterChannel,这个例程会在一个合适的时候调用它的一个回调函数
  3. 回调函数内部会根据IRP的MDL得到内核虚拟地址,接着MapTransfer,调用会得到物理地址,这个物理地址是指总线相关的物理地址
  4. 得到物理地址后,一般是写入硬件寄存器,并且通知启动DMA传输
  5. 真正的DMA传输就开始了

这种方式的DMA是可以直接把硬件的数据DMA到应用层的,效率相当高。另外DDK文档说明了一些Cache的控制,以及映射寄存器(x86是软件模拟的)的一些关系。需要仔细推敲和理解

使用公共缓冲区的传输是比较简单的:

  1. 在StartDevice时,AllocateCommonBuffer得到一个公共缓冲区,这个缓冲区是物理连续的,有时候是会失败的。如果失败,那么StartDevice应该返回STATUS_INSUFFICIENT_RESOURCES.
  2. 和基于包的一样,IRP到达Dispacher,Dispacher直接使用缓冲区域地址编程硬件就可以启动DMA了
  3. 这个公共缓冲区需要在RemoveDevice时应该释放,FreeCommonBuffer是用来释放它的。

这种方式的DMA的代码是对少的,但他有一个缺点,数据只能到驱动,不能直接到达应用层,但可以通过拷贝到达应用层。无疑这是有效率问题的。

关于这两种方式的选择,DDK是这样建议的

如果驱动可以知道设备传输数据的开始和结束,使用包方式。否则,使用公共缓冲区。为什么呢?

DMA传输时,几乎完全是硬件行为,由于包方式的DMA,其地址是不连续的,那么DMA必定分多个阶段,每个阶段必须重新编程硬件。每个阶段都要中断主机,中断内如果无法判断全部传输结束,最终就会无法在合适的时候完成IRP。而公共缓冲区的方式,地址是连续的,设备可以在结束时才中断主机。

另外,这两种方式并不互斥,可以即有包方式,又有公共缓冲区。比如,公共缓冲区放一些多次传输的信息,以表示传输的结束,多次DMA后,ISR可以根据这些信息判断结束,最终完成IRP

除了基本的DMA方式,如果设备具备在不连续的物理地址上传输(Scatter/Gather特性),可以使用Scatter/Gather传输。关于Scatter/Gather方式和基于包的方式不做讨论了

 

总线主控DMA(续)

上一次分析了DMA两种方式,基于包的DMA方式和CommonBuffer方式。

最近看文档和资料,其实CommonBuffer是可以直接让应用程序访问的,具体的资料在 DDK文档的Using Common-Buffer System DMA这一节

实际的过程是这样的

AllocateCommonBuffer有两个产物,返回值是虚拟地址VirtualAddr,另一个参数返回一个逻辑地址LogicAddr。LogicAddr是DMA控制器理解的地址,用于MapTransfer。而VirtualAddr是系统可以理解的地址,在驱动层是可以直接使用这个地址来访问CommonBuffer的。如果要在应用层访问,需要以下步骤:

  1. IoAllocateMdl传递VirtualAddr得到一个MDL
  2. 得到的MDL传递给MmBuildMdlForNonPagedPool,以便锁定物理内存不被换出
  3. 调用MmMapLockedPages把虚拟地址映射到UserMode
  4. 完成IRP时只要把这个地址返回,应用层便可以直接使用这个地址来访问CommonBuffer了

用这种方法可以更有效利用DMA,特别是一些数据量大的场合。最后就是合理划分DMA的CommonBuffer,并不一定要一个连续的很大的物理内存。这就和硬件相关了,比如硬件一批数据是10M,那就分配N个10M的CommonBuffer,而不是一个N*10M的。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值