當前位置:首頁 > 嵌入式 > 嵌入式分享
[導讀]從我們的直觀感受來說,DMA并不是一個復(fù)雜的東西,要做的事情也很單純直白。因此Linux kernel對它的抽象和實現(xiàn),也應(yīng)該簡潔、易懂才是。不過現(xiàn)實卻不甚樂觀(個人感覺),Linux kernel dmaengine framework的實現(xiàn),真有點晦澀的感覺。為什么會這樣呢?

從我們的直觀感受來說,DMA并不是一個復(fù)雜的東西,要做的事情也很單純直白。因此Linux kernel對它的抽象和實現(xiàn),也應(yīng)該簡潔、易懂才是。不過現(xiàn)實卻不甚樂觀(個人感覺),Linux kernel dmaengine framework的實現(xiàn),真有點晦澀的感覺。為什么會這樣呢?

1.前言

如果一個軟件模塊比較復(fù)雜、晦澀,要么是設(shè)計者的功力不夠,要么是需求使然。當然,我們不敢對Linux kernel的那些大神們有絲毫懷疑和不敬,只能從需求上下功夫了:難道Linux kernel中的driver對DMA的使用上,有一些超出了我們?nèi)粘5恼J知范圍?

要回答這些問題并不難,將dmaengine framework為consumers提供的功能和API梳理一遍就可以了,這就是本文的目的。當然,也可以借助這個過程,加深對DMA的理解,以便在編寫那些需要DMA傳輸?shù)膁river的時候,可以更游刃有余。

2. Slave-DMA API和Async TX API

從方向上來說,DMA傳輸可以分為4類:memory到memory、memory到device、device到memory以及device到device。Linux kernel作為CPU的代理人,從它的視角看,外設(shè)都是slave,因此稱這些有device參與的傳輸(MEM2DEV、DEV2MEM、DEV2DEV)為Slave-DMA傳輸。而另一種memory到memory的傳輸,被稱為Async TX。

為什么強調(diào)這種差別呢?因為Linux為了方便基于DMA的memcpy、memset等操作,在dma engine之上,封裝了一層更為簡潔的API(如下面圖片1所示),這種API就是Async TX API(以async_開頭,例如async_memcpy、async_memset、async_xor等)。

圖片1 DMA Engine API示意圖

最后,因為memory到memory的DMA傳輸有了比較簡潔的API,沒必要直接使用dma engine提供的API,最后就導致dma engine所提供的API就特指為Slave-DMA API(把mem2mem剔除了)。

本文主要介紹dma engine為consumers提供的功能和API,因此就不再涉及Async TX API了(具體可參考本站后續(xù)的文章。

注1:Slave-DMA中的“slave”,指的是參與DMA傳輸?shù)脑O(shè)備。而對應(yīng)的,“master”就是指DMA controller自身。一定要明白“slave”的概念,才能更好的理解kernel dma engine中有關(guān)的術(shù)語和邏輯。

3. dma engine的使用步驟

注2:本文大部分內(nèi)容翻譯自kernel document[1],喜歡讀英語的讀者可以自行參考。

對設(shè)備驅(qū)動的編寫者來說,要基于dma engine提供的Slave-DMA API進行DMA傳輸?shù)脑挘枰缦碌牟僮鞑襟E:

1)申請一個DMA channel。

2)根據(jù)設(shè)備(slave)的特性,配置DMA channel的參數(shù)。

3)要進行DMA傳輸?shù)臅r候,獲取一個用于識別本次傳輸(transaction)的描述符(descriptor)。

4)將本次傳輸(transacTIon)提交給dma engine并啟動傳輸。

5)等待傳輸(transacTIon)結(jié)束。

然后,重復(fù)3~5即可。

上面5個步驟,除了3有點不好理解外,其它的都比較直觀易懂,具體可參考后面的介紹。

3.1 申請DMA channel

任何consumer(文檔[1]中稱作client,也可稱作slave driver,意思都差不多,不再特意區(qū)分)在開始DMA傳輸之前,都要申請一個DMA channel(有關(guān)DMA channel的概念,請參考[2]中的介紹)。

DMA channel(在kernel中由“struct dma_chan”數(shù)據(jù)結(jié)構(gòu)表示)由provider(或者是DMA controller)提供,被consumer(或者client)使用。對consumer來說,不需要關(guān)心該數(shù)據(jù)結(jié)構(gòu)的具體內(nèi)容(我們會在dmaengine provider的介紹中在詳細介紹)。

consumer可以通過如下的API申請DMA channel:

struct dma_chan *dma_request_chan(struct device *dev, const char *name);

該接口會返回綁定在指定設(shè)備(dev)上名稱為name的dma channel。dma engine的provider和consumer可以使用device tree、ACPI或者struct dma_slave_map類型的match table提供這種綁定關(guān)系,具體可參考XXXX章節(jié)的介紹。

最后,申請得到的dma channel可以在不需要使用的時候通過下面的API釋放掉:

void dma_release_channel(struct dma_chan *chan);

3.2 配置DMA channel的參數(shù)

driver申請到一個為自己使用的DMA channel之后,需要根據(jù)自身的實際情況,以及DMA controller的能力,對該channel進行一些配置??膳渲玫膬?nèi)容由struct dma_slave_config數(shù)據(jù)結(jié)構(gòu)表示(具體可參考4.1小節(jié)的介紹)。driver將它們填充到一個struct dma_slave_config變量中后,可以調(diào)用如下API將這些信息告訴給DMA controller:

int dmaengine_slave_config(struct dma_chan *chan, struct dma_slave_config *config)

3.3 獲取傳輸描述(tx descriptor)

DMA傳輸屬于異步傳輸,在啟動傳輸之前,slave driver需要將此次傳輸?shù)囊恍┬畔?例如src/dst的buffer、傳輸?shù)姆较虻?提交給dma engine(本質(zhì)上是dma controller driver),dma engine確認okay后,返回一個描述符(由struct dma_async_tx_descriptor抽象)。此后,slave driver就可以以該描述符為單位,控制并跟蹤此次傳輸。

struct dma_async_tx_descriptor數(shù)據(jù)結(jié)構(gòu)可參考4.2小節(jié)的介紹。根據(jù)傳輸模式的不同,slave driver可以使用下面三個API獲取傳輸描述符(具體可參考DocumentaTIon/dmaengine/client.txt[1]中的說明):

struct dma_async_tx_descriptor *dmaengine_prep_slave_sg(

struct dma_chan *chan, struct scatterlist *sgl,

unsigned int sg_len, enum dma_data_direcTIon direction,

unsigned long flags);

struct dma_async_tx_descriptor *dmaengine_prep_dma_cyclic(

struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,

size_t period_len, enum dma_data_direction direction);

struct dma_async_tx_descriptor *dmaengine_prep_interleaved_dma(

struct dma_chan *chan, struct dma_interleaved_template *xt,

unsigned long flags);

dmaengine_prep_slave_sg用于在“scatter gather buffers”列表和總線設(shè)備之間進行DMA傳輸,參數(shù)如下:

注3:有關(guān)scatterlist 我們在[3][2]中有提及,后續(xù)會有專門的文章介紹它,這里暫且按下不表。

chan,本次傳輸所使用的dma channel。

sgl,要傳輸?shù)摹皊catter gather buffers”數(shù)組的地址;

sg_len,“scatter gather buffers”數(shù)組的長度。

direction,數(shù)據(jù)傳輸?shù)姆较颍唧w可參考enum dma_data_direction (include/linux/dma-direction.h)的定義。

flags,可用于向dma controller driver傳遞一些額外的信息,包括(具體可參考enum dma_ctrl_flags中以DMA_PREP_開頭的定義):

DMA_PREP_INTERRUPT,告訴DMA controller driver,本次傳輸完成后,產(chǎn)生一個中斷,并調(diào)用client提供的回調(diào)函數(shù)(可在該函數(shù)返回后,通過設(shè)置struct dma_async_tx_descriptor指針中的相關(guān)字段,提供回調(diào)函數(shù),具體可參考4.2小節(jié)的介紹);

DMA_PREP_FENCE,告訴DMA controller driver,后續(xù)的傳輸,依賴本次傳輸?shù)慕Y(jié)果(這樣controller driver就會小心的組織多個dma傳輸之間的順序);

DMA_PREP_PQ_DISABLE_P、DMA_PREP_PQ_DISABLE_Q、DMA_PREP_CONTINUE,PQ有關(guān)的操作,TODO。

dmaengine_prep_dma_cyclic常用于音頻等場景中,在進行一定長度的dma傳輸(buf_addr&buf_len)的過程中,每傳輸一定的byte(period_len),就會調(diào)用一次傳輸完成的回調(diào)函數(shù),參數(shù)包括:

chan,本次傳輸所使用的dma channel。

buf_addr、buf_len,傳輸?shù)腷uffer地址和長度。

period_len,每隔多久(單位為byte)調(diào)用一次回調(diào)函數(shù)。需要注意的是,buf_len應(yīng)該是period_len的整數(shù)倍。

direction,數(shù)據(jù)傳輸?shù)姆较颉?

dmaengine_prep_interleaved_dma可進行不連續(xù)的、交叉的DMA傳輸,通常用在圖像處理、顯示等場景中,具體可參考struct dma_interleaved_template結(jié)構(gòu)的定義和解釋(這里不再詳細介紹,需要用到的時候,再去學習也okay)。

3.4 啟動傳輸

通過3.3章節(jié)介紹的API獲取傳輸描述符之后,client driver可以通過dmaengine_submit接口將該描述符放到傳輸隊列上,然后調(diào)用dma_async_issue_pending接口,啟動傳輸。

dmaengine_submit的原型如下:

dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)

參數(shù)為傳輸描述符指針,返回一個唯一識別該描述符的cookie,用于后續(xù)的跟蹤、監(jiān)控。

dma_async_issue_pending的原型如下:

void dma_async_issue_pending(struct dma_chan *chan);

參數(shù)為dma channel,無返回值。

注4:由上面兩個API的特征可知,kernel dma engine鼓勵client driver一次提交多個傳輸,然后由kernel(或者dma controller driver)統(tǒng)一完成這些傳輸。

3.5 等待傳輸結(jié)束

傳輸請求被提交之后,client driver可以通過回調(diào)函數(shù)獲取傳輸完成的消息,當然,也可以通過dma_async_is_tx_complete等API,測試傳輸是否完成。不再詳細說明了。

最后,如果等不及了,也可以使用dmaengine_pause、dmaengine_resume、dmaengine_terminate_xxx等API,暫停、終止傳輸,具體請參考kernel document[1]以及source code。

4. 重要數(shù)據(jù)結(jié)構(gòu)說明

4.1 struct dma_slave_config

中包含了完成一次DMA傳輸所需要的所有可能的參數(shù),其定義如下:

/* include/linux/dmaengine.h */

struct dma_slave_config {

enum dma_transfer_direction direction;

phys_addr_t src_addr;

phys_addr_t dst_addr;

enum dma_slave_buswidth src_addr_width;

enum dma_slave_buswidth dst_addr_width;

u32 src_maxburst;

u32 dst_maxburst;

bool device_fc;

unsigned int slave_id;

};

direction,指明傳輸?shù)姆较?,包?具體可參考enum dma_transfer_direction的定義和注釋):

DMA_MEM_TO_MEM,memory到memory的傳輸;

DMA_MEM_TO_DEV,memory到設(shè)備的傳輸;

DMA_DEV_TO_MEM,設(shè)備到memory的傳輸;

DMA_DEV_TO_DEV,設(shè)備到設(shè)備的傳輸。

注5:controller不一定支持所有的DMA傳輸方向,具體要看provider的實現(xiàn)。

注6:參考第2章的介紹,MEM to MEM的傳輸,一般不會直接使用dma engine提供的API。

src_addr,傳輸方向是dev2mem或者dev2dev時,讀取數(shù)據(jù)的位置(通常是固定的FIFO地址)。對mem2dev類型的channel,不需配置該參數(shù)(每次傳輸?shù)臅r候會指定);

dst_addr,傳輸方向是mem2dev或者dev2dev時,寫入數(shù)據(jù)的位置(通常是固定的FIFO地址)。對dev2mem類型的channel,不需配置該參數(shù)(每次傳輸?shù)臅r候會指定);

src_addr_width、dst_addr_width,src/dst地址的寬度,包括1、2、3、4、8、16、32、64(bytes)等(具體可參考enum dma_slave_buswidth 的定義)。

src_maxburst、dst_maxburst,src/dst最大可傳輸?shù)腷urst size(可參考[2]中有關(guān)burst size的介紹),單位是src_addr_width/dst_addr_width(注意,不是byte)。

device_fc,當外設(shè)是Flow Controller(流控制器)的時候,需要將該字段設(shè)置為true。CPU中有關(guān)DMA和外部設(shè)備之間連接方式的設(shè)計中,決定DMA傳輸是否結(jié)束的模塊,稱作flow controller,DMA controller或者外部設(shè)備,都可以作為flow controller,具體要看外設(shè)和DMA controller的設(shè)計原理、信號連接方式等,不在詳細說明(感興趣的同學可參考[4]中的介紹)。

slave_id,外部設(shè)備通過slave_id告訴dma controller自己是誰(一般和某個request line對應(yīng))。很多dma controller并不區(qū)分slave,只要給它src、dst、len等信息,它就可以進行傳輸,因此slave_id可以忽略。而有些controller,必須清晰地知道此次傳輸?shù)膶ο笫悄膫€外設(shè),就必須要提供slave_id了(至于怎么提供,可dma controller的硬件以及驅(qū)動有關(guān),要具體場景具體對待)。

4.2 struct dma_async_tx_descriptor

傳輸描述符用于描述一次DMA傳輸(類似于一個文件句柄)。client driver將自己的傳輸請求通過3.3中介紹的API提交給dma controller driver后,controller driver會返回給client driver一個描述符。

client driver獲取描述符后,可以以它為單位,進行后續(xù)的操作(啟動傳輸、等待傳輸完成、等等)。也可以將自己的回調(diào)函數(shù)通過描述符提供給controller driver。

傳輸描述符的定義如下:

struct dma_async_tx_descriptor {

dma_cookie_t cookie;

enum dma_ctrl_flags flags; /* not a ‘long’ to pack with cookie */

dma_addr_t phys;

struct dma_chan *chan;

dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);

int (*desc_free)(struct dma_async_tx_descriptor *tx);

dma_async_tx_callback callback;

void *callback_param;

struct dmaengine_unmap_data *unmap;

#ifdef CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH

struct dma_async_tx_descriptor *next;

struct dma_async_tx_descriptor *parent;

spinlock_t lock;

#endif

};

cookie,一個整型數(shù),用于追蹤本次傳輸。一般情況下,dma controller driver會在內(nèi)部維護一個遞增的number,每當client獲取傳輸描述的時候(參考3.3中的介紹),都會將該number賦予cookie,然后加一。

注7:有關(guān)cookie的使用場景,我們會在后續(xù)的文章中再詳細介紹。

flags, DMA_CTRL_開頭的標記,包括:

DMA_CTRL_REUSE,表明這個描述符可以被重復(fù)使用,直到它被清除或者釋放;

DMA_CTRL_ACK,如果該flag為0,表明暫時不能被重復(fù)使用。

phys,該描述符的物理地址??不太懂!

chan,對應(yīng)的dma channel。

tx_submit,controller driver提供的回調(diào)函數(shù),用于把改描述符提交到待傳輸列表。通常由dma engine調(diào)用,client driver不會直接和該接口打交道。

desc_free,用于釋放該描述符的回調(diào)函數(shù),由controller driver提供,dma engine調(diào)用,client driver不會直接和該接口打交道。

callback、callback_param,傳輸完成的回調(diào)函數(shù)(及其參數(shù)),由client driver提供。

后面其它參數(shù),client driver不需要關(guān)心,暫不描述了。

5. 參考文檔

[1] Documentation/dmaengine/client.txt

[2] Linux DMA Engine framework(1)_概述

[3] Linux MMC framework(2)_host controller driver

[4] https://forums.xilinx.com/xlnx/attachments/xlnx/ELINUX/10658/1/drivers-session4-dma-4public.pdf

以上就是今天的介紹啦,你了解了嗎?

本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團)股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉