蛻變成蝶:Linux裝置驅動之DMA

李輝發表於2016-04-30

DMA概述

DMA是一種無需CPU的參加就可以讓外設與系統記憶體之間進行雙向資料傳輸的硬體機制。它可以使系統CPU從實際的I/O資料傳輸過程中擺脫出來,大大提高系統的吞吐率,並且在傳輸期間,CPU還可以併發執行其他任務。

DMA與cache的一致性

cache用作CPU針對記憶體的快取,避免CPU每一次都要與相對來說慢點的記憶體互動資料,從而來提高資料的訪問速率,而DMA可以用作記憶體與外設之間傳輸資料的方式,資料不需要經過CPU週轉。

“假設裝置驅動程式把一些資料填充到記憶體緩衝區中,然後立刻命令硬體裝置利用DMA傳送方式讀取該資料。如果DMA訪問這些物理RAM記憶體單元,而相應的硬體快取記憶體行的內容還沒有寫入RAM中,那麼硬體裝置所讀取的至就是記憶體緩衝區中的舊值。”

現在有兩種方法來處理DMA緩衝區:

一致性DMA對映:
書上講的比較抽象,通俗地所就是任何對DMA緩衝區的改寫都會直接更新到記憶體中,也稱之為“同步的”或者“一致的”。

流式DMA對映:
根據個人的理解,這裡的流即輸入輸出流,我們需要事先指定DMA緩衝區的方向。

啟動一次流式DMA資料傳輸分為如下步驟(本DMA驅動開發介紹僅適合S3C2410處理器型別):

1. 分配DMA緩衝區
在DMA裝置不採用S/G(分散/聚集)模式的情況下,必須保證緩衝區是物理上連續的,linux核心有兩個函式用來分配連續的記憶體:kmalloc()和__get_free_pages()。這兩個函式都有分配連續記憶體的最大值,kmalloc以分配位元組為單位,最大約為64KB,__get_free_pages()以分配頁為單位,最大能分配2^order數目的頁,order引數的最大值由include/linux/Mmzone.h檔案中的MAX_ORDER巨集決定(在預設的2.6.18核心版本中,該巨集定義為10。也就是說在理論上__get_free_pages函式一次最多能申請1<<10 * 4KB也就是4MB的連續實體記憶體,在Xilinx Zynq Linux核心中,該巨集定義為11)。

2. 建立流式對映

在對DMA衝區進行讀寫訪問之後,且在啟動DMA裝置傳輸之前,啟用dma_map_single()函式建立流式DMA對映,這兩個函式接受緩衝區的線性地址作為其引數並返回相應的匯流排地址。

3. 釋放流式對映
當DMA傳輸結束之後我們需要釋放該對映,這時呼叫dma_unmap_single()函式。

注意:

(1). 為了避免快取記憶體一致性問題,驅動程式在開始從RAM到裝置的DMA資料傳輸之前,如果有必要,應該呼叫dma_sync_single_for_device()函式重新整理與DMA緩衝區對應的快取記憶體行。

(2). 從裝置到RAM的一次DMA資料傳送完成之前裝置驅動程式是不可以訪問記憶體緩衝區的,但如果有必要的話,驅動程式在讀緩衝區之前,應該呼叫dma_sync_single_for_cpu()函式使相應的硬體快取記憶體行無效。

(3). 雖然kmalloc底層也是用__get_free_pages實現的,不過kmalloc對應的釋放緩衝區函式為kfree,而__get_free_pages對應的釋放緩衝區函式為free_pages。具體與__get_free_pages有關係的幾個申請與釋放函式如下:

申請函式:

釋放函式:

DMA驅動主要資料結構:

1)DMA單個核心緩衝區資料結構:

2)DMA暫存器資料結構:

3)DMA裝置資料結構

4)DMA通道資料結構

DMA驅動主要函式功能分析:

寫一個DMA驅動的主要工作包括:DMA通道申請、DMA中斷申請、控制暫存器設定、掛入DMA等待佇列、清除DMA中斷、釋放DMA通道.

函式描述:申請某通道的DMA資源,填充s3c2410_dma_t 資料結構的內容,申請DMA中斷。

輸入引數:device_id DMA 裝置名;channel 通道號;

write_cb DMA寫操作完成的回撥函式;read_cb DMA讀操作完成的回撥函式

輸出引數:若channel通道已使用,出錯返回;否則,返回0

函式描述:這是DMA操作最關鍵的函式,它完成了一系列動作:分配並初始化一個DMA核心緩衝區控制結構,並將它插入DMA等待佇列,設定DMA控制暫存器內容,等待DMA操作觸發

輸入引數: channel 通道號;buf_id,緩衝區標識

dma_addr_t data DMA資料緩衝區起始實體地址;size DMA資料緩衝區大小;write 是寫還是讀操作

輸出引數:操作成功,返回0;否則,返回錯誤號

函式描述:停止DMA操作。

函式描述:釋放DMA通道所申請的所有記憶體資源

函式描述:釋放DMA通道

因為各函式功能強大,一個完整的DMA驅動程式中一般只需呼叫以上3個函式即可。可在驅動初始化中呼叫s3c2410_request_dma,開始DMA傳輸前呼叫s3c2410_dma_queue_buffer,釋放驅動模組時呼叫s3c2410_free_dma。

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

蛻變成蝶:Linux裝置驅動之DMA 蛻變成蝶:Linux裝置驅動之DMA

相關文章