利用WinDriver實現鏈式DMA
使用鏈式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的倍數的要求。
存儲器相關文章:存儲器原理
評論