五 DMA及Cache一致性

整體目錄

一 linux虛擬內存、MMU、分頁的基本原理
二 OOM打分因子、oom_adj以及oom_score
三 頁的alloc與free、Buddy算法以及CMA
四 page_fault、內存IO交互、VSS、LRU
五 DMA及Cache一致性

=================================================================================

cache的作用:

  • CPU在訪問內存時,首先判斷所要訪問的內容是否在Cache中,如果在,就稱爲“命中(hit)”,此時CPU直接從Cache中調用該內容;否則,就稱爲“missing”,CPU只好去內存中調用所需的子程序或指令了。
  • CPU不但可以直接從Cache中讀出內容,也可以直接往其中寫入內容。
  • Cache的存取速率相當快,使得CPU的利用率大大提高,進而使整個系統的性能得以提升。
  • Cache的一致性就是直Cache中的數據,與對應的內存中的數據是一致的。

dma的作用:

  • DMA是直接操作總線地址的,這裏先當作物理地址來看待(系統總線地址和物理地址只是觀察內存的角度不同)。如果cache緩存的內存區域不包括DMA分配到的區域,那麼就沒有一致性的問題。但是如果cache緩存包括了DMA目的地址的話,一致性就會有問題,因爲經過DMA操作,cache緩存對應的內存數據已經被修改了,而CPU本身不知道(DMA傳輸是不通過CPU的),它仍然認爲cache中的數據就是內存中的數據,以後訪問Cache映射的內存時,它仍然使用舊的Cache數據。這樣就發生Cache與內存的數據“不一致性”錯誤。
    總線地址是從設備角度上看到的內存,物理地址是CPU的角度看到的未經過轉換的內存(經過轉換的是虛擬地址)

=============================================================

出現內存不一致的原因

CPU寫內存的時候有兩種方式:

  1. write through: CPU直接寫內存,不經過cache。
  2. write back: CPU只寫到cache中。cache的硬件使用LRU算法將cache裏面的內容替換到內存。通常是這種方式。

DMA可以完成從內存到外設直接進行數據搬移。但DMA不能訪問CPU的cache,CPU在讀內存的時候,如果cache命中則只是在cache去讀,而不是從內存讀,寫內存的時候,也可能實際上沒有寫到內存,而只是直接寫到了cache。

這樣一來,如果DMA從將數據從外設寫到內存,CPU中cache中的數據(如果有的話)就是舊數據了,這時CPU在讀內存的時候命中cache了,就是讀到了舊數據;CPU寫數據到內存時,如果只是先寫到了cache,則內存裏的數據就是舊數據了。這兩種情況(兩個方向)都存在cache一致性問題。例如,網卡發包的時候,CPU將數據寫到cache,而網卡的DMA從內存裏去讀數據,就發送了錯誤的數據。
在這裏插入圖片描述

如何解決一致性問題

1.一致性DMA緩存(Coherent DMA buffers)

DMA需要的內存由內核去申請,內核可能需要對這段內存重新做一遍映射,特點是映射的時候標記這些頁是不帶cache的,這個特性也是存放在頁表裏面的。
上面說“可能”需要重新做映射,如果內核在highmem映射區申請內存並將這個地址通過vmap映射到vmalloc區域,則需要修改相應頁表項並將頁面設置爲非cache的,而如果內核從lowmem申請內存,我們知道這部分是已經線性映射好了,因此不需要修改頁表,只需修改相應頁表項爲非cache即可。
相關的接口就是dma_alloc_coherent()和dma_free_coherent()。dma_alloc_coherent()會傳一個device結構體指明給哪個設備申請一致性DMA內存,它會產生兩個地址,一個是給CPU看的,一個是給DMA看的。CPU需要通過返回的虛擬地址來訪問這段內存,纔是非cache的。至於dma_alloc_coherent()的內部實現可以不關注,它是和體系結構如何實現非cache(如mips的kseg1)相關,也可能與硬件特性(如是否支持CMA)相關。
因爲內存是可cache的,因此在DMA讀內存(內存到設備方向)時,由於cache中可能有新的數據,因此要先將cache中的數據寫回到內存(writeback );在DMA寫內存(設備到內存方向)時,cache中可能還有數據沒有寫回,爲了防止cache數據覆蓋DMA要寫的內容,要先將cache無效(invalidate )。注意這個函數的vaddr參數接收的是虛擬地址。

2.流式DMA映射(DMA Streaming Mapping)

相關接口爲
dma_map_sg(), dma_unmap_sg(),
dma_map_single(),dma_unmap_single()。
流式DMA映射實現比較複雜,生命週期比較短,而且禁用cache。一些硬件對流式映射有優化。建立流式DMA映射,需要告訴內核數據的流動方向; dma_alloc_writecombine

=============================================================

參考資料

具體可以查看該網址:Linux內存管理 —— DMA和一致性緩存

發佈了6 篇原創文章 · 獲贊 1 · 訪問量 7736
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章