dma_alloc_coherent: 一致性DMA映射
dma_alloc_writecombine: 流式DMA映射
原來 dma_alloc_coherent 在 arm 平台上會禁止頁表項中的 C (Cacheable) 域以及 B (Bufferable)域。
而 dma_alloc_writecombine 只禁止 C (Cacheable) 域.
#define pgprot_noncached(prot) __pgprot(pgprot_val(prot) & ~(L_PTE_CACHEABLE | L_PTE_BUFFERABLE))
#define pgprot_writecombine(prot) __pgprot(pgprot_val(prot) & ~L_PTE_CACHEABLE)
進一步尋找 ARM 書籍, 原來 C 代表是否使用高速緩衝儲存空間, 而 W 代表是否使用寫緩衝區。
這樣, dma_alloc_coherent 分配出來的記憶體不使用緩衝,也不會使用寫緩衝區。
而 dma_alloc_writecombine 則不使用緩衝,但是使用寫緩衝區。
即一致性 DMA 映射由於關閉了 cache/buffer, 效能自然比較低。 而流式則通過複雜的同步機制,沒有付出效能的代價。
所以我們要盡量使用流式 DMA 來編程。
再去看看 mmc 驅動裡使用的 分散 / 聚集映射, 原來也是一種 流式 DMA 映射。
【補充】
講了那麼多沒用,總結下用法:
1、頁對齊記憶體大小:dma_map_size = PAGE_ALIGN(MY_DATA_SIZE + PAGE_SIZE);
MY_DATA_SIZE是你想分配的大小.
2、調用
A = dma_alloc_writecombine(B,C,D,GFP_KERNEL);
含義:
A: 記憶體的虛擬起始地址,在核心要用此地址來操作所分配的記憶體
B: struct device指標,可以平台初始化裡指定,主要是dma_mask之類,可參考framebuffer
C: 實際分配大小,傳入dma_map_size即可
D: 返回的記憶體物理地址,dma就可以用。
所以,A和D是一一對應的,只不過,A是虛擬位址,而D是物理地址。對任意一個操作都將改變緩衝區內容。當然要注意作業環境。