利用WinDriver实现链式DMA

时间:2013-07-13来源:网络

使用链式DMA传输数据时,主机首先通过设置DMA控制寄存器,告诉设备要传输数据的描述符表的起始地址和描述符的个数,然后启动DMA传输。设备收到启动DMA传输的命令后,首先根据主机提供的描述符表信息,检索相应的描述符,并存储到设备的FIFO中,然后根据每一个描述符中的地址和长度信息,进行相应的DMA数据传输。所有的DMA描述符处理完成后,设备更新描述符头的EPLAST域。主机便可通过查询EPLA ST域获得链式DMA传输完成的信息,从而可以启动下一次链式DMA传输。

2 WinDrivet中的DMA功能
WinDriver是Jungo公司提供的一种通用的驱动开发支持软件,它简化了用户的上层驱动开发和应用接口开发,而且易于再封装,实现商业化应用。该软件提供了对PCIExpress接口设备的驱动支持,而且也提供了对DMA实现功能的支持。
WinDriver提供了两种DMA缓冲区的分配方式,即连续缓冲区和分散/聚合缓冲区。前者当用户申请缓冲区时,分配的是一个物理地址连续的内存块;而后者分配的缓冲区在物理位置上可以是分段的,这些物理上不连续的内存段通过虚拟地址空间映射给用户的是一个在应用层连续的缓冲区。
由于采用DMA传输数据时,设备需要的主机地址是物理地址;而在主机端,申请大块的物理地址连续的内存区域往往是非常困难的。因此在使用DMA进行大量数据传输时,主机端使用分散/聚合缓冲区分配方式更方便和易于实现。此时,主机可以将缓冲区的每个内存段对应一个描述符,这样采用链式DMA方式可以解决大的内存区域物理地址不连续的问题,方便了大存储区域数据的传输。

3 具体实现
在具体实现时,主机是通过访问的设备的BAR2地址空间来设置DMA控制寄存器的。DMA控制寄存器分为DMA读控制寄存器和DMA写控制寄存器,它们均是由4个32位的双字组成,依次表示的含义是:控制域和描述表中描述符的个数、描述符表的高32位地址、描述符表的低32位地址、最后一个描述符的索引,其中第一个双字的控制域部分用来控制在每个描述符传输完成时设备是否更新主机描述符头的EPLAST域。DMA写(即数据由设备向主机传送)控制寄存器的开始地址位于BAR2地址空间的0字节偏移地址处,DMA读(即数据由主机向设备传送)控制寄存器的开始地址位于BAR2地址空间的16字节偏移地址处。主机可以通过调用WinDriver提供的API函数WDC_WriteAddr32每次设置DMA读/写控制寄存器的一个双字。
在每次DMA传输开始时,根据设备DMA的设计要求,必须先调用WDC_WriteAddr32函数向DMA读/写控制寄存器的第一个双字写入0xFFFF的内容,以使设备DMA进入到可以工作的状态。这是因为设备每次执行完DMA操作后,处于停止工作状态,只有通过对控制寄存器的第一个双字写0xFFFF才能使设备DMA模块退出停止状态,重新准备检索DMA描述符。详见样本工程的ahpcierd_dma_descriptor模块的状态机部分。
需要注意的是,描述表的描述符中的主机低32位地址必须是16的倍数,设备地址也必须是16的倍数。这是因为设备的端点存储器是一个带有字节写使能控制的RAM,且其每个周期读写16个字节的数据。对于DMA读操作来说,设备收到主机的带数据的完成包后,是根据主机端的地址设置端点存储器的字节写使能控制信号的。如果主机端地址的低4位与设备端地址的低4位不一致,将导致数据起始存储位置不正确。例如:如果主机端地址的低4位是8,设备端地址的低4位是0,端点存储器写的数据总线接收数据的第一有效时钟周期内接收的16字节数据,低8字节对应的字节使能位是0,高8个字节才是有效的数据。这些有效数据被写入端点存储器规定存储位置向后偏移8个字节的地方,这显然与设备要求的存储位置不符。
对于DMA写操作来说,设备从端点存储器中读取数据时,直接将设备地址的低4位丢弃了,所以设备地址也应为16的倍数。如果主机端地址低32位不是16的倍数,根据设备的Descriptor/Data Interface处理规则和PCI Express规范中存储器写事务包的处理规则,将导致主机收到的数据包的有效数据位置向后偏移,部分有效数据丢失,例如:如果主机端低32位地址的低4位是8,那么将使得从端点存储器读取的数据的前8个字节丢失,主机端收到的数据的开始位置比预期位置向后移了8个字节。
在设置主机的描述表时,先调用WinDriver提供的API函数WDC_DMASGBufLock对申请的进行DMA数据传输的内存块进行锁定,然后根据锁定的页数,确定描述表中描述符的个数,每个描述符对应其中的1页存储区域。根据上面对主机低32位地址的要求,在申请进行DMA传输的内存区域时,申请的空间大小可以比实际需要存储区域多16个字节。这样,在调用WDC_DMASGBufLock函数对申请的内存块进行锁定后,如果第一页的物理地址不是16的倍数(在多页的情况下,后面的页的物理地址均为16的倍数),可以DMA传输的实际区域向后移动相应的位置,以使数据存储的开始位置的物理地址为16的倍数。例如,如果第1页物理地址的低4位是4,那么可以向后移动12个字节作为DMA传输的开始位置。如果申请的空间由多页组成,应注意第1页对应的描述符传输数据的长度将减少,及对后面页对应描述符的设备地址的影响。
设置完成DMA传输的描述符表后,需要通过设置DMA控制寄存器,告诉设备主机描述表的起始物理地址和描述符的个数。这里,也有上面类似的要求。即要求描述表的低32位地址为16的倍数,否则将导致设备FIFO每个周期接收的描述符不是一个完整的描述符,即可能是由前一个描述符的后8字节和后一个描述符的前8字节组成。这将导致以后DMA数据传输的混乱和错误。为此,在调用WDC_DMASGBufLock函数对描述符表存储区域进行锁定时,可以进行上面类似的地址对齐处理。
因为在调用WDC_DMASGBufLock函数对一块存储区域进行锁定时,中间页的大小均是4 KB的倍数。这样就可以估算出一块内存区域大概可以分成几页,从而估计出描述符表由几个描述符组成。比如文中的设备存储器是一个32 KB的端点存储器,因此进行一次DMA传输的描述符个数不超过9个,描述符表占用的存储空间为:16+9*16=160字节。对于这种描述表所需空间少于2 KB的情况下,可以采用如下策略使得描述表的数据集中到一个物理页中,以便于对DMA控制寄存器的设置,即如果所需空间为x(x≤2032)字节,那么申请2(x+16)字节(≤4 KB)的空间,这样在调用WDC_DMASGBufLock函数进行存储区域锁定时,得到的页数最多为2页,且至少有一页的大小不小于x+16字节。于是,便可用此页作为描述符表的存储区域,并使描述符表的起始地址满足16的倍数的要求。
1 2 3

关键词: 链式DMA WinDriver PCI Express 端点存储器

加入微信
获取电子行业最新资讯
搜索微信公众号:EEPW

或用微信扫描左侧二维码

相关文章

查看电脑版