日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

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

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

1.前言

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

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

2. Slave-DMA API和Async TX API

從方向上來(lái)說(shuō),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。

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

圖片1 DMA Engine API示意圖

最后,因?yàn)閙emory到memory的DMA傳輸有了比較簡(jiǎn)潔的API,沒(méi)必要直接使用dma engine提供的API,最后就導(dǎo)致dma engine所提供的API就特指為Slave-DMA API(把mem2mem剔除了)。

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

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

3. dma engine的使用步驟

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

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

1)申請(qǐng)一個(gè)DMA channel。

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

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

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

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

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

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

3.1 申請(qǐng)DMA channel

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

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

consumer可以通過(guò)如下的API申請(qǐng)DMA channel:

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

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

最后,申請(qǐng)得到的dma channel可以在不需要使用的時(shí)候通過(guò)下面的API釋放掉:

void dma_release_channel(struct dma_chan *chan);

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

driver申請(qǐng)到一個(gè)為自己使用的DMA channel之后,需要根據(jù)自身的實(shí)際情況,以及DMA controller的能力,對(duì)該channel進(jìn)行一些配置??膳渲玫膬?nèi)容由struct dma_slave_config數(shù)據(jù)結(jié)構(gòu)表示(具體可參考4.1小節(jié)的介紹)。driver將它們填充到一個(gè)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傳輸屬于異步傳輸,在啟動(dòng)傳輸之前,slave driver需要將此次傳輸?shù)囊恍┬畔?例如src/dst的buffer、傳輸?shù)姆较虻?提交給dma engine(本質(zhì)上是dma controller driver),dma engine確認(rèn)okay后,返回一個(gè)描述符(由struct dma_async_tx_descriptor抽象)。此后,slave driver就可以以該描述符為單位,控制并跟蹤此次傳輸。

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

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è)備之間進(jìn)行DMA傳輸,參數(shù)如下:

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

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

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

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

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

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

DMA_PREP_INTERRUPT,告訴DMA controller driver,本次傳輸完成后,產(chǎn)生一個(gè)中斷,并調(diào)用client提供的回調(diào)函數(shù)(可在該函數(shù)返回后,通過(guò)設(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就會(huì)小心的組織多個(gè)dma傳輸之間的順序);

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

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

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

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

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

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

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

3.4 啟動(dòng)傳輸

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

dmaengine_submit的原型如下:

dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)

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

dma_async_issue_pending的原型如下:

void dma_async_issue_pending(struct dma_chan *chan);

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

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

3.5 等待傳輸結(jié)束

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

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

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

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的實(shí)現(xiàn)。

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

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

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

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

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

4.2 struct dma_async_tx_descriptor

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

client driver獲取描述符后,可以以它為單位,進(jìn)行后續(xù)的操作(啟動(dòng)傳輸、等待傳輸完成、等等)。也可以將自己的回調(diào)函數(shù)通過(guò)描述符提供給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,一個(gè)整型數(shù),用于追蹤本次傳輸。一般情況下,dma controller driver會(huì)在內(nèi)部維護(hù)一個(gè)遞增的number,每當(dāng)client獲取傳輸描述的時(shí)候(參考3.3中的介紹),都會(huì)將該number賦予cookie,然后加一。

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

flags, DMA_CTRL_開(kāi)頭的標(biāo)記,包括:

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

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

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

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

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

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

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)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請(qǐng)聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請(qǐng)及時(shí)聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動(dòng)電源

在工業(yè)自動(dòng)化蓬勃發(fā)展的當(dāng)下,工業(yè)電機(jī)作為核心動(dòng)力設(shè)備,其驅(qū)動(dòng)電源的性能直接關(guān)系到整個(gè)系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動(dòng)勢(shì)抑制與過(guò)流保護(hù)是驅(qū)動(dòng)電源設(shè)計(jì)中至關(guān)重要的兩個(gè)環(huán)節(jié),集成化方案的設(shè)計(jì)成為提升電機(jī)驅(qū)動(dòng)性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機(jī) 驅(qū)動(dòng)電源

LED 驅(qū)動(dòng)電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個(gè)照明設(shè)備的使用壽命。然而,在實(shí)際應(yīng)用中,LED 驅(qū)動(dòng)電源易損壞的問(wèn)題卻十分常見(jiàn),不僅增加了維護(hù)成本,還影響了用戶體驗(yàn)。要解決這一問(wèn)題,需從設(shè)計(jì)、生...

關(guān)鍵字: 驅(qū)動(dòng)電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動(dòng)電源的公式,電感內(nèi)電流波動(dòng)大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計(jì) 驅(qū)動(dòng)電源

電動(dòng)汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動(dòng)汽車的核心技術(shù)之一是電機(jī)驅(qū)動(dòng)控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機(jī)驅(qū)動(dòng)系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動(dòng)汽車的動(dòng)力性能和...

關(guān)鍵字: 電動(dòng)汽車 新能源 驅(qū)動(dòng)電源

在現(xiàn)代城市建設(shè)中,街道及停車場(chǎng)照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進(jìn)步,高亮度白光發(fā)光二極管(LED)因其獨(dú)特的優(yōu)勢(shì)逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動(dòng)電源 LED

LED通用照明設(shè)計(jì)工程師會(huì)遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動(dòng)電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動(dòng)電源的電磁干擾(EMI)問(wèn)題成為了一個(gè)不可忽視的挑戰(zhàn)。電磁干擾不僅會(huì)影響LED燈具的正常工作,還可能對(duì)周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來(lái)解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動(dòng)電源

開(kāi)關(guān)電源具有效率高的特性,而且開(kāi)關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機(jī)重量也有所下降,所以,現(xiàn)在的LED驅(qū)動(dòng)電源

關(guān)鍵字: LED 驅(qū)動(dòng)電源 開(kāi)關(guān)電源

LED驅(qū)動(dòng)電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動(dòng)LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動(dòng)電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動(dòng)電源
關(guān)閉