利用WinDriver實(shí)現(xiàn)鏈?zhǔn)紻MA
使用鏈?zhǔn)紻MA傳輸數(shù)據(jù)時,主機(jī)首先通過設(shè)置DMA控制寄存器,告訴設(shè)備要傳輸數(shù)據(jù)的描述符表的起始地址和描述符的個數(shù),然后啟動DMA傳輸。設(shè)備收到啟動DMA傳輸?shù)拿詈?,首先根?jù)主機(jī)提供的描述符表信息,檢索相應(yīng)的描述符,并存儲到設(shè)備的FIFO中,然后根據(jù)每一個描述符中的地址和長度信息,進(jìn)行相應(yīng)的DMA數(shù)據(jù)傳輸。所有的DMA描述符處理完成后,設(shè)備更新描述符頭的EPLAST域。主機(jī)便可通過查詢EPLA ST域獲得鏈?zhǔn)紻MA傳輸完成的信息,從而可以啟動下一次鏈?zhǔn)紻MA傳輸。
2 WinDrivet中的DMA功能
WinDriver是Jungo公司提供的一種通用的驅(qū)動開發(fā)支持軟件,它簡化了用戶的上層驅(qū)動開發(fā)和應(yīng)用接口開發(fā),而且易于再封裝,實(shí)現(xiàn)商業(yè)化應(yīng)用。該軟件提供了對PCIExpress接口設(shè)備的驅(qū)動支持,而且也提供了對DMA實(shí)現(xiàn)功能的支持。
WinDriver提供了兩種DMA緩沖區(qū)的分配方式,即連續(xù)緩沖區(qū)和分散/聚合緩沖區(qū)。前者當(dāng)用戶申請緩沖區(qū)時,分配的是一個物理地址連續(xù)的內(nèi)存塊;而后者分配的緩沖區(qū)在物理位置上可以是分段的,這些物理上不連續(xù)的內(nèi)存段通過虛擬地址空間映射給用戶的是一個在應(yīng)用層連續(xù)的緩沖區(qū)。
由于采用DMA傳輸數(shù)據(jù)時,設(shè)備需要的主機(jī)地址是物理地址;而在主機(jī)端,申請大塊的物理地址連續(xù)的內(nèi)存區(qū)域往往是非常困難的。因此在使用DMA進(jìn)行大量數(shù)據(jù)傳輸時,主機(jī)端使用分散/聚合緩沖區(qū)分配方式更方便和易于實(shí)現(xiàn)。此時,主機(jī)可以將緩沖區(qū)的每個內(nèi)存段對應(yīng)一個描述符,這樣采用鏈?zhǔn)紻MA方式可以解決大的內(nèi)存區(qū)域物理地址不連續(xù)的問題,方便了大存儲區(qū)域數(shù)據(jù)的傳輸。
3 具體實(shí)現(xiàn)
在具體實(shí)現(xiàn)時,主機(jī)是通過訪問的設(shè)備的BAR2地址空間來設(shè)置DMA控制寄存器的。DMA控制寄存器分為DMA讀控制寄存器和DMA寫控制寄存器,它們均是由4個32位的雙字組成,依次表示的含義是:控制域和描述表中描述符的個數(shù)、描述符表的高32位地址、描述符表的低32位地址、最后一個描述符的索引,其中第一個雙字的控制域部分用來控制在每個描述符傳輸完成時設(shè)備是否更新主機(jī)描述符頭的EPLAST域。DMA寫(即數(shù)據(jù)由設(shè)備向主機(jī)傳送)控制寄存器的開始地址位于BAR2地址空間的0字節(jié)偏移地址處,DMA讀(即數(shù)據(jù)由主機(jī)向設(shè)備傳送)控制寄存器的開始地址位于BAR2地址空間的16字節(jié)偏移地址處。主機(jī)可以通過調(diào)用WinDriver提供的API函數(shù)WDC_WriteAddr32每次設(shè)置DMA讀/寫控制寄存器的一個雙字。
在每次DMA傳輸開始時,根據(jù)設(shè)備DMA的設(shè)計要求,必須先調(diào)用WDC_WriteAddr32函數(shù)向DMA讀/寫控制寄存器的第一個雙字寫入0xFFFF的內(nèi)容,以使設(shè)備DMA進(jìn)入到可以工作的狀態(tài)。這是因為設(shè)備每次執(zhí)行完DMA操作后,處于停止工作狀態(tài),只有通過對控制寄存器的第一個雙字寫0xFFFF才能使設(shè)備DMA模塊退出停止?fàn)顟B(tài),重新準(zhǔn)備檢索DMA描述符。詳見樣本工程的ahpcierd_dma_descriptor模塊的狀態(tài)機(jī)部分。
需要注意的是,描述表的描述符中的主機(jī)低32位地址必須是16的倍數(shù),設(shè)備地址也必須是16的倍數(shù)。這是因為設(shè)備的端點(diǎn)存儲器是一個帶有字節(jié)寫使能控制的RAM,且其每個周期讀寫16個字節(jié)的數(shù)據(jù)。對于DMA讀操作來說,設(shè)備收到主機(jī)的帶數(shù)據(jù)的完成包后,是根據(jù)主機(jī)端的地址設(shè)置端點(diǎn)存儲器的字節(jié)寫使能控制信號的。如果主機(jī)端地址的低4位與設(shè)備端地址的低4位不一致,將導(dǎo)致數(shù)據(jù)起始存儲位置不正確。例如:如果主機(jī)端地址的低4位是8,設(shè)備端地址的低4位是0,端點(diǎn)存儲器寫的數(shù)據(jù)總線接收數(shù)據(jù)的第一有效時鐘周期內(nèi)接收的16字節(jié)數(shù)據(jù),低8字節(jié)對應(yīng)的字節(jié)使能位是0,高8個字節(jié)才是有效的數(shù)據(jù)。這些有效數(shù)據(jù)被寫入端點(diǎn)存儲器規(guī)定存儲位置向后偏移8個字節(jié)的地方,這顯然與設(shè)備要求的存儲位置不符。
對于DMA寫操作來說,設(shè)備從端點(diǎn)存儲器中讀取數(shù)據(jù)時,直接將設(shè)備地址的低4位丟棄了,所以設(shè)備地址也應(yīng)為16的倍數(shù)。如果主機(jī)端地址低32位不是16的倍數(shù),根據(jù)設(shè)備的Descriptor/Data Interface處理規(guī)則和PCI Express規(guī)范中存儲器寫事務(wù)包的處理規(guī)則,將導(dǎo)致主機(jī)收到的數(shù)據(jù)包的有效數(shù)據(jù)位置向后偏移,部分有效數(shù)據(jù)丟失,例如:如果主機(jī)端低32位地址的低4位是8,那么將使得從端點(diǎn)存儲器讀取的數(shù)據(jù)的前8個字節(jié)丟失,主機(jī)端收到的數(shù)據(jù)的開始位置比預(yù)期位置向后移了8個字節(jié)。
在設(shè)置主機(jī)的描述表時,先調(diào)用WinDriver提供的API函數(shù)WDC_DMASGBufLock對申請的進(jìn)行DMA數(shù)據(jù)傳輸?shù)膬?nèi)存塊進(jìn)行鎖定,然后根據(jù)鎖定的頁數(shù),確定描述表中描述符的個數(shù),每個描述符對應(yīng)其中的1頁存儲區(qū)域。根據(jù)上面對主機(jī)低32位地址的要求,在申請進(jìn)行DMA傳輸?shù)膬?nèi)存區(qū)域時,申請的空間大小可以比實(shí)際需要存儲區(qū)域多16個字節(jié)。這樣,在調(diào)用WDC_DMASGBufLock函數(shù)對申請的內(nèi)存塊進(jìn)行鎖定后,如果第一頁的物理地址不是16的倍數(shù)(在多頁的情況下,后面的頁的物理地址均為16的倍數(shù)),可以DMA傳輸?shù)膶?shí)際區(qū)域向后移動相應(yīng)的位置,以使數(shù)據(jù)存儲的開始位置的物理地址為16的倍數(shù)。例如,如果第1頁物理地址的低4位是4,那么可以向后移動12個字節(jié)作為DMA傳輸?shù)拈_始位置。如果申請的空間由多頁組成,應(yīng)注意第1頁對應(yīng)的描述符傳輸數(shù)據(jù)的長度將減少,及對后面頁對應(yīng)描述符的設(shè)備地址的影響。
設(shè)置完成DMA傳輸?shù)拿枋龇砗?,需要通過設(shè)置DMA控制寄存器,告訴設(shè)備主機(jī)描述表的起始物理地址和描述符的個數(shù)。這里,也有上面類似的要求。即要求描述表的低32位地址為16的倍數(shù),否則將導(dǎo)致設(shè)備FIFO每個周期接收的描述符不是一個完整的描述符,即可能是由前一個描述符的后8字節(jié)和后一個描述符的前8字節(jié)組成。這將導(dǎo)致以后DMA數(shù)據(jù)傳輸?shù)幕靵y和錯誤。為此,在調(diào)用WDC_DMASGBufLock函數(shù)對描述符表存儲區(qū)域進(jìn)行鎖定時,可以進(jìn)行上面類似的地址對齊處理。
因為在調(diào)用WDC_DMASGBufLock函數(shù)對一塊存儲區(qū)域進(jìn)行鎖定時,中間頁的大小均是4 KB的倍數(shù)。這樣就可以估算出一塊內(nèi)存區(qū)域大概可以分成幾頁,從而估計出描述符表由幾個描述符組成。比如文中的設(shè)備存儲器是一個32 KB的端點(diǎn)存儲器,因此進(jìn)行一次DMA傳輸?shù)拿枋龇麄€數(shù)不超過9個,描述符表占用的存儲空間為:16+9*16=160字節(jié)。對于這種描述表所需空間少于2 KB的情況下,可以采用如下策略使得描述表的數(shù)據(jù)集中到一個物理頁中,以便于對DMA控制寄存器的設(shè)置,即如果所需空間為x(x≤2032)字節(jié),那么申請2(x+16)字節(jié)(≤4 KB)的空間,這樣在調(diào)用WDC_DMASGBufLock函數(shù)進(jìn)行存儲區(qū)域鎖定時,得到的頁數(shù)最多為2頁,且至少有一頁的大小不小于x+16字節(jié)。于是,便可用此頁作為描述符表的存儲區(qū)域,并使描述符表的起始地址滿足16的倍數(shù)的要求。
存儲器相關(guān)文章:存儲器原理
評論