1.概述
DMA(Direct Memory Access)是計算機系統中除了CPU之外可以主動訪問計算機系統內存的硬件部件,DMA的主要功能搬移內存數據而不用通過CPU核。
有些CPU會設計通用DMA設備給各外設使用,例如嵌入式CPU的一些低速外設,自身沒有設計DMA,為了數據傳輸的高效,則需要借用通用DMA設備。
對于大多數的高速外設,因其業務特性,是會自己實現相應的DMA組件的,以追求業務最佳性能。
針對通用DMA設備,Linux系統中提供了統一的DMA驅動框架——DMA子系統。
2. DMA類型
DMA從不同的角度可以進行不同的分類:
2.1 DMA mapping方式分類
從DMA mapping方式可以分為2類:
Coherent DMA(一致性DMA)
Coherent DMA訪問內存地址時不過cache,是cache-coherence設備,采用Consistent mapping的API進行內存申請;
Streaming DMA(流式DMA)
Streaming DMA在訪問內存地址時經過cache,是non-coherence設備,通常采用streaming mapping的API進行內存申請,在單次DMA傳輸時進行map,在傳輸完成后進行unmap;
2.2 DMA工作方式分類
從DMA工作方式可以分為2類:
Block DMA
硬件DMA設計為一次訪問操作需要連續內存地址空間;
Scatter-Gather DMA
硬件DMA設計為一次訪問操作可以訪問多個離散的、不連續的內存地址空間,并將不連續地址空間的進行數據組合;
兩種類型的DMA明顯差異是軟件配置給DMA的地址格式不同,Block DMA只需要在寄存器中實現地址寄存器和數據長度寄存器即可;但Scatter-Gather DMA需要采用描述符表的方式,描述符表中每一個條目是各離散地址和數據長度,寄存器只需要實現描述符表的基址寄存器。
3. Linux DMA子系統
3.1 DMA子系統框架
DMA子系統是一個相對比較簡單的子系統,整個框架比較薄,Linux下DMA子系統的框架圖見下圖藍色部分:
Linux DMA子系統主要有有5部分組成:
dmaengine:
是DMA子系統的核心,為DMA Device Driver提供DMA設備注冊的API,為DMA調用者(Device Driver)提供屏蔽DMA設備實現細節的統一接口API;
virt-dma:
為DMA子系統提供虛擬DMA channel的支持;
of-dma:
為DMA子系統提供設備樹描述DMA信息傳入的支持;
DMA Device Driver:
為DMA設備的驅動程序;
dmatest:
提供dmatest模塊測試DMA memcpy, memset, XOR和RAID6 P+Q操作各種長度和各種偏移量進入源和目標緩沖區;
3.2 DMA子系統重要API
此處主要介紹DMA系統為上、下游提供的API,dma-mapping的API此處不做介紹。
3.2.1 Register API
1)dma_async_device_register
將DMA設備驅動注冊到dma子系統;
int dma_async_device_register(struct dma_device *device)
2)dma_async_device_unregister
將DMA設備驅動從dma子系統注銷;
void dma_async_device_unregister(struct dma_device *device)
3.2.2 DMA調用者(Device Driver)API
1)dma_request_chan
查找并返回與設備關聯的設備名為name的DMA通道,這種關聯是通過設備樹描述實現的。
通過該接口申請的channel是獨占的,直到使用dma_release_channel()釋放為止。
struct dma_chan *dma_request_chan(struct device *dev, const char *name)
2)dmaengine_slave_config
傳遞指定的信息給DMA驅動,這些信息大部分已經集成在struct dma_slave_config中賦值;
如果需要傳遞更多的信息,可以將struct dma_slave_config內嵌到DMA設備的指定結構體中,這種就可以傳遞更多參數了;
int dmaengine_slave_config(struct dma_chan *chan, struct dma_slave_config *config)
3)dmaengine_prep_slave_sg
以散列表的形式傳輸數據,在調用dmaengine_prep_slave_sg()之前需要使用散列表的映射,并且必須在DMA操作完成之前不能釋放。如果需要同步,請調用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
把描述符添加到掛起的隊列中來;
dma_cookie_t dmaengine_submit(struct dma_async_tx_descriptor *desc)
5)dma_async_issue_pending
激活掛起隊列中的事務,一旦一個事務完成,隊列中的下一個事務就開啟,如果設置了回調,還會調用回調以通知完成;
void dma_async_issue_pending(struct dma_chan *chan)
審核編輯:黃飛
?
評論
查看更多