1.概述
DMA(Direct Memory Access)是計(jì)算機(jī)系統(tǒng)中除了CPU之外可以主動(dòng)訪問(wèn)計(jì)算機(jī)系統(tǒng)內(nèi)存的硬件部件,DMA的主要功能搬移內(nèi)存數(shù)據(jù)而不用通過(guò)CPU核。
有些CPU會(huì)設(shè)計(jì)通用DMA設(shè)備給各外設(shè)使用,例如嵌入式CPU的一些低速外設(shè),自身沒(méi)有設(shè)計(jì)DMA,為了數(shù)據(jù)傳輸?shù)母咝В瑒t需要借用通用DMA設(shè)備。
對(duì)于大多數(shù)的高速外設(shè),因其業(yè)務(wù)特性,是會(huì)自己實(shí)現(xiàn)相應(yīng)的DMA組件的,以追求業(yè)務(wù)最佳性能。
針對(duì)通用DMA設(shè)備,Linux系統(tǒng)中提供了統(tǒng)一的DMA驅(qū)動(dòng)框架——DMA子系統(tǒng)。
2. DMA類(lèi)型
DMA從不同的角度可以進(jìn)行不同的分類(lèi):
2.1 DMA mapping方式分類(lèi)
從DMA mapping方式可以分為2類(lèi):
Coherent DMA(一致性DMA)
Coherent DMA訪問(wèn)內(nèi)存地址時(shí)不過(guò)cache,是cache-coherence設(shè)備,采用Consistent mapping的API進(jìn)行內(nèi)存申請(qǐng);
Streaming DMA(流式DMA)
Streaming DMA在訪問(wèn)內(nèi)存地址時(shí)經(jīng)過(guò)cache,是non-coherence設(shè)備,通常采用streaming mapping的API進(jìn)行內(nèi)存申請(qǐng),在單次DMA傳輸時(shí)進(jìn)行map,在傳輸完成后進(jìn)行unmap;
2.2 DMA工作方式分類(lèi)
從DMA工作方式可以分為2類(lèi):
Block DMA
硬件DMA設(shè)計(jì)為一次訪問(wèn)操作需要連續(xù)內(nèi)存地址空間;
Scatter-Gather DMA
硬件DMA設(shè)計(jì)為一次訪問(wèn)操作可以訪問(wèn)多個(gè)離散的、不連續(xù)的內(nèi)存地址空間,并將不連續(xù)地址空間的進(jìn)行數(shù)據(jù)組合;
兩種類(lèi)型的DMA明顯差異是軟件配置給DMA的地址格式不同,Block DMA只需要在寄存器中實(shí)現(xiàn)地址寄存器和數(shù)據(jù)長(zhǎng)度寄存器即可;但Scatter-Gather DMA需要采用描述符表的方式,描述符表中每一個(gè)條目是各離散地址和數(shù)據(jù)長(zhǎng)度,寄存器只需要實(shí)現(xiàn)描述符表的基址寄存器。
3. Linux DMA子系統(tǒng)
3.1 DMA子系統(tǒng)框架
DMA子系統(tǒng)是一個(gè)相對(duì)比較簡(jiǎn)單的子系統(tǒng),整個(gè)框架比較薄,Linux下DMA子系統(tǒng)的框架圖見(jiàn)下圖藍(lán)色部分:

Linux DMA子系統(tǒng)主要有有5部分組成:
dmaengine:
是DMA子系統(tǒng)的核心,為DMA Device Driver提供DMA設(shè)備注冊(cè)的API,為DMA調(diào)用者(Device Driver)提供屏蔽DMA設(shè)備實(shí)現(xiàn)細(xì)節(jié)的統(tǒng)一接口API;
virt-dma:
為DMA子系統(tǒng)提供虛擬DMA channel的支持;
of-dma:
為DMA子系統(tǒng)提供設(shè)備樹(shù)描述DMA信息傳入的支持;
DMA Device Driver:
為DMA設(shè)備的驅(qū)動(dòng)程序;
dmatest:
提供dmatest模塊測(cè)試DMA memcpy, memset, XOR和RAID6 P+Q操作各種長(zhǎng)度和各種偏移量進(jìn)入源和目標(biāo)緩沖區(qū);
3.2 DMA子系統(tǒng)重要API
此處主要介紹DMA系統(tǒng)為上、下游提供的API,dma-mapping的API此處不做介紹。
3.2.1 Register API
1)dma_async_device_register
將DMA設(shè)備驅(qū)動(dòng)注冊(cè)到dma子系統(tǒng);
int dma_async_device_register(struct dma_device *device)
2)dma_async_device_unregister
將DMA設(shè)備驅(qū)動(dòng)從dma子系統(tǒng)注銷(xiāo);
void dma_async_device_unregister(struct dma_device *device)
3.2.2 DMA調(diào)用者(Device Driver)API
1)dma_request_chan
查找并返回與設(shè)備關(guān)聯(lián)的設(shè)備名為name的DMA通道,這種關(guān)聯(lián)是通過(guò)設(shè)備樹(shù)描述實(shí)現(xiàn)的。
通過(guò)該接口申請(qǐng)的channel是獨(dú)占的,直到使用dma_release_channel()釋放為止。
struct dma_chan *dma_request_chan(struct device *dev, const char *name)
2)dmaengine_slave_config
傳遞指定的信息給DMA驅(qū)動(dòng),這些信息大部分已經(jīng)集成在struct dma_slave_config中賦值;
如果需要傳遞更多的信息,可以將struct dma_slave_config內(nèi)嵌到DMA設(shè)備的指定結(jié)構(gòu)體中,這種就可以傳遞更多參數(shù)了;
int dmaengine_slave_config(struct dma_chan *chan, struct dma_slave_config *config)
3)dmaengine_prep_slave_sg
以散列表的形式傳輸數(shù)據(jù),在調(diào)用dmaengine_prep_slave_sg()之前需要使用散列表的映射,并且必須在DMA操作完成之前不能釋放。如果需要同步,請(qǐng)調(diào)用dma_sync_*_for_*();
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);
4)dmaengine_submit
把描述符添加到掛起的隊(duì)列中來(lái);
dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
5)dma_async_issue_pending
激活掛起隊(duì)列中的事務(wù),一旦一個(gè)事務(wù)完成,隊(duì)列中的下一個(gè)事務(wù)就開(kāi)啟,如果設(shè)置了回調(diào),還會(huì)調(diào)用回調(diào)以通知完成;
void dma_async_issue_pending(struct dma_chan *chan)
審核編輯:黃飛
?
電子發(fā)燒友App




























評(píng)論