本文轉(zhuǎn)自公眾號(hào)歡迎關(guān)注
一.描述符概述
1.0 前言
對(duì)于DWC Ethernet QoS驅(qū)動(dòng)的編寫(xiě)來(lái)說(shuō),初始化完成之后,核心操作就是DMA的描述符鏈表配置(linked list of descriptors)。DMA根據(jù)描述符鏈表自動(dòng)在FIFO和用戶指定的緩存之間搬運(yùn)數(shù)據(jù)。對(duì)于熟悉新思的IP的用戶來(lái)說(shuō),這種套路會(huì)有似曾相識(shí)的感覺(jué),沒(méi)錯(cuò)新思的大部分高速I(mǎi)P的數(shù)據(jù)流都是這么處理的,比如在DWC2 USB的IP中就是Scatter/Gather DMA,叫法不一樣,實(shí)現(xiàn)和思想基本是一樣的。這種方式可以解放CPU,使用DMA根據(jù)描述符鏈表搬運(yùn)數(shù)據(jù),對(duì)于高速數(shù)據(jù)流的流式處理有利,相對(duì)單個(gè)描述符的DMA,鏈表式描述符一次可以處理更多數(shù)據(jù)更高效,且能夠?qū)崿F(xiàn)環(huán)形不間斷流式處理。
參考手冊(cè)《21 Descriptors》
1.1描述符類(lèi)型
Normal Descriptor: 描述要傳輸?shù)臄?shù)據(jù)包和其控制信息。包含兩個(gè)緩沖區(qū)和兩個(gè)地址指針,這種設(shè)計(jì)以實(shí)現(xiàn)較大的靈活性,支持不同的內(nèi)存管理方案。
Context Descriptor: 描述要傳輸?shù)臄?shù)據(jù)包的控制信息。
注意:單個(gè)數(shù)據(jù)包可以使用的描述符數(shù)量沒(méi)有限制,雖然這里沒(méi)有限制,但是受限于Ring_Length寄存器,描述符鏈表實(shí)際最多只能配置為0x3FF即1024個(gè)描述符。
1.2描述符結(jié)構(gòu)
描述鏈表整體看是一個(gè)環(huán)形結(jié)構(gòu)即到了描述符的末尾可以繞回.
有一些寄存器對(duì)該環(huán)形描述符進(jìn)行定義
1.2.1描述符的顆粒(間隙)
收發(fā)都是一樣的
上述描述Descriptor n本身的大小是固定的即RDES0~RDES3,4個(gè)WORD(根據(jù)不同的總線寬度和大小端,有不同的layout,但是其大小總是4個(gè)WORD大小,見(jiàn)后面說(shuō)明).
還支持描述符之間有間隙,間隙的單位根據(jù)總線寬度而定,即32,64,128位總線寬度分別對(duì)應(yīng) Word, Dword, Lword為單位,寄存器DMA_CH(#i)_Control的DSL位域即用于描述該間隙。
再次提醒注意,這里的單位是根據(jù)總線寬度而定,不是固定為WORD。
比如這里DSL=0,則表示描述符之間沒(méi)有間隙,
設(shè)置為1,如果是32位總線則間隙為1 WORD。
1.2.2描述符的個(gè)數(shù)
收發(fā)分別由如下寄存器指定
DMA_CH(#i)_TxDesc_Ring_Length
DMA_CH(#i)_RxDesc_Ring_Length
1.2.3描述符的首末地址
1)發(fā)由以下寄存器決定:
基地址
DMA_CHi_Tx_Control的ST=0,即TX停止時(shí)才能修改以下寄存器。
DMA_CH(#i)_TxDesc_List_HAddress 發(fā)送描述符鏈表基地址的高位,只有40,48位地址模式才使用。
DMA_CH(#i)_TxDesc_List_Address 發(fā)送描述符鏈表基地址的低位,必須根據(jù)總線寬度按照Word, Dword,Lword對(duì)齊,DMA會(huì)自動(dòng)根據(jù)總線寬度忽略低位。
尾地址
DMA_CH(#i)_TxDesc_Tail_Pointer 發(fā)送描述符鏈表尾地址,必須根據(jù)總線寬度按照Word, Dword,Lword對(duì)齊。
這里為什么沒(méi)有高位寄存器了呢,因?yàn)椴恍枰耍呶缓虳MA_CH(#i)_TxDesc_List_HAddress一樣。
2)收由以下寄存器決定 :
基地址
DMA_CH(#i)_RX_Control 的SR=0,即RX停止時(shí)才能修改以下寄存器。
DMA_CH(#i)_RxDesc_List_HAddress 接收描述符鏈表基地址的高位,只有40,48位地址模式才使用。
DMA_CH(#i)_RxDesc_List_Address
接收描述符鏈表基地址的低位,必須根據(jù)總線寬度按照Word, Dword,Lword對(duì)齊,DMA會(huì)自動(dòng)根據(jù)總線寬度忽略低位。
尾地址
DMA_CH(#i)_RxDesc_Tail_Pointer接收描述符鏈表尾地址,必須根據(jù)總線寬度按照Word, Dword,Lword對(duì)齊。
這里為什么沒(méi)有高位寄存器了呢,因?yàn)椴恍枰耍呶缓虳MA_CH(#i)_RxDesc_List_HAddress一樣。
1.2.4當(dāng)前處理的Buffer地址
以下只讀寄存器可以調(diào)試使用,確認(rèn)當(dāng)前處理的描述符對(duì)應(yīng)的Buffer地址,reset時(shí)這些寄存器會(huì)清零。
發(fā)送Buffer
DMA_CH(#i)_Current_App_TxBuffer_H 地址高位
DMA_CH(#i)_Current_App_TxBuffer 地址低位
接收Buffer
DMA_CH(#i)_Current_App_RxBuffer_H
DMA_CH(#i)_Current_App_RxBuffer
需要有收發(fā)數(shù)據(jù)才會(huì)更新當(dāng)前處理的Buffer地址。
1.2.5當(dāng)前描述符指針
以下只讀寄存器可以調(diào)試使用,確認(rèn)當(dāng)前處理的描述符,reset時(shí)這些寄存器會(huì)清零。
發(fā)送
DMA_CH(#i)_Current_App_TxDesc
接收
DMA_CH(#i)_Current_App_RxDesc
Current寄存器是什么時(shí)候更新的呢,測(cè)試可以知道是寫(xiě)B(tài)ase寄存器時(shí)更新
進(jìn)一步測(cè)試可知是在DMA停止,即DMA_CH(#i)_RX_Control的SR為0時(shí)寫(xiě)DMA_CH(#i)_RxDesc_List_Address 時(shí)Current寄存器會(huì)自動(dòng)設(shè)置為DMA_CH(#i)_RxDesc_List_Address的值。如果SR=1則不會(huì)。
TX也類(lèi)似。在DMA工作之后,該寄存器更新為當(dāng)前正在處理的描述符。
1.3描述符的內(nèi)存布局
描述符的大小總是4x4字節(jié)的,但是其布局和總線寬度和大小端有關(guān)。
且必須根據(jù)總線寬度Word, DWord,或 LWord 對(duì)齊。
三種總線寬度,2種大小端模式一共有6種組合
32位的大端和小端
64位小端
64位大端
128位小端
128位大端
1.4描述鏈表的工作過(guò)程
1.4.1環(huán)形結(jié)構(gòu)
前面介紹的描述符首末地址,當(dāng)前描述符指針和描述符個(gè)數(shù)這幾個(gè)寄存器決定了鏈表的行為。
DMA可以處理的描述符范圍是:[Base,Tail)
注意[]表示包括本身,()表示不包括本身,即包括Base寄存器對(duì)應(yīng)的描述符,不包括Tail寄存器對(duì)應(yīng)的描述符。
當(dāng)前描述符指針則從Base到Tail-1的位置遍歷,當(dāng)Current=Tai時(shí)DMA停止工作。
同時(shí)還受描述符個(gè)數(shù)寄存器限制,
如果描述個(gè)數(shù)設(shè)置為N,則Current到Base~N-1的位置之后會(huì)繞回到Base,即以N個(gè)為單位回環(huán),這里假設(shè)Tail是在N個(gè)描述符之后的,如果在之前則回環(huán)之前就Current=Tail停止了。
1.4.2停止條件:
Current=Tail
或者Current的位置沒(méi)有就緒的描述符,即不是Owned by DMA的描述符。
所以Tail至少要大于base才能傳輸。
1.4.3重啟條件
重啟條件即保證current處的描述符就緒,且current%N
寫(xiě)Tail寄存器時(shí)會(huì)觸發(fā)一次硬件的重啟條件檢測(cè),來(lái)檢測(cè)上述條件。
所以停止了之后讀寫(xiě) 都需要寫(xiě)Tail寄存器才能重啟 。
1.4.4幾種情況分析
Tail 指向 N-1位置之后,此時(shí)current不可能達(dá)到tail,因?yàn)榈絅-1時(shí)就繞回了,
所以停止條件只能是current處的描述符未就緒,即不是Owned by DMA。
此時(shí)current不斷回環(huán)遍歷,只要軟件能保證current處的描述符一直就緒,DMA就一直傳輸處理,形成了不間斷的持續(xù)流處理。
Tail剛好指向N-1位置或者更向前
則當(dāng)current=current后停止。
或者current處的描述符未就緒即停止。
此時(shí)沒(méi)法形成持續(xù)的流,因?yàn)閏urrent到了tail之后就會(huì)停止。
1.4.5驅(qū)動(dòng)的設(shè)計(jì)
為了充分利用上述描述符的回環(huán)模式,能夠連續(xù)不斷的收發(fā),需要保證DMA處理完之前就更新好后續(xù)描述符。使得DMA一直有描述符能處理,不至于current處描述符未就緒而導(dǎo)致停止,且tail設(shè)置為在N個(gè)描述符之后,這樣current始終不會(huì)因?yàn)?tail而停止。
要保證連續(xù)不斷的流,需要軟件準(zhǔn)備描述符的速度大于等于DMA處理描述符的速度。
即current處始終有描述符可以處理,所以軟件準(zhǔn)備好的描述符在current及其之后,需要軟件維護(hù)一個(gè)變量index記錄當(dāng)前軟件準(zhǔn)備好的描述到了哪。
即current追趕index。
當(dāng)index>current時(shí),[current,index)之間是已經(jīng)準(zhǔn)備好的描述符待DMA處理的,[index,Tail)
[base,current)這兩部分是DMA已經(jīng)處理完,軟件需要更新的描述符。
當(dāng)index<=current時(shí),[index,current)是DMA已經(jīng)處理完,軟件需要更新的描述符。
[current,Tail),[Base,index)這兩部分是DMA未處理的部分。
所以驅(qū)動(dòng)處理流程如下
初始化時(shí)先盡可能多的填充好描述符,對(duì)于接收可以初始化所有描述符為接收狀態(tài),對(duì)于發(fā)送當(dāng)然剛開(kāi)始可能并不需要發(fā)送很多數(shù)據(jù),那么就需要發(fā)送多少就準(zhǔn)備多少描述符。
然后接收中斷中處理DMA已經(jīng)接收完的描述符,應(yīng)用處理完對(duì)應(yīng)的數(shù)據(jù)后再將這些描述符設(shè)置為接收狀態(tài)。
對(duì)于發(fā)送則查詢哪些描述符DMA已經(jīng)發(fā)送完就可將其更新為發(fā)送狀態(tài)進(jìn)行發(fā)送。
比如如下開(kāi)始準(zhǔn)備了n個(gè)描述符
然后啟動(dòng)DMA傳輸,
此時(shí)有兩種情況,一種是硬件處理DMA比如軟件更新描述符塊,還有一種是相反。
后者軟件總是在current追不上index,即軟件更新描述符速度大于硬件處理描述符速度
一段時(shí)間后可能就是如下所示
而前者軟件準(zhǔn)備的慢則current會(huì)追上index此時(shí)DMA會(huì)停止,軟件需要重新準(zhǔn)備描述符并重新配置Tail來(lái)重啟DMA。
具體的驅(qū)動(dòng)代碼后面再詳講。
1.5總結(jié)
以上介紹了描述符鏈表,尤其需要了解環(huán)形鏈表的工作模式何時(shí)啟動(dòng),何時(shí)停止,軟件和硬件如何配合使用環(huán)形鏈表。以及相關(guān)寄存器的值的含義和何時(shí)更新。了解以上機(jī)制后后面就可以開(kāi)始編寫(xiě)驅(qū)動(dòng)代碼進(jìn)行收發(fā)。下回再詳講。
審核編輯 黃宇
-
嵌入式
+關(guān)注
關(guān)注
5082文章
19122瀏覽量
305108 -
以太網(wǎng)
+關(guān)注
關(guān)注
40文章
5423瀏覽量
171684 -
寄存器
+關(guān)注
關(guān)注
31文章
5343瀏覽量
120332 -
驅(qū)動(dòng)
+關(guān)注
關(guān)注
12文章
1840瀏覽量
85287 -
dma
+關(guān)注
關(guān)注
3文章
561瀏覽量
100572
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論