宋寶華: 關於DMA ZONE和dma alloc coherent若干誤解的完全澄清

原創 宋寶華 Linux閱碼場 2018-01-22html


做者簡介
宋寶華,他有10幾年的Linux開發經驗。他長期在大型企業擔任一線工程師和系統架構師,編寫大量的Linux代碼,並負責在gerrit上review其餘同事的代碼。Barry Song是Linux的活躍開發者,是某些內核版本的最活躍開發者之一(如https://lwn.net/Articles/395961/ 、https://lwn.net/Articles/429912/),也曾是一ARM SoC系列在Linux mainline的maintainer。他也是china-pub等評估的2008年度「十大暢銷經典」,「十佳原創精品」圖書《Linux設備驅動開發詳解》的做者和《Essential Linux Device Driver》的譯者。同時書寫了不少技術文章,是51CTO 2012年度「十大傑出IT博客」得主及51CTO、CSDN的專家博主。他也熱衷於開源項目,正在開發LEP(Linux Easy Profiling,http://www.linuxep.com/)項目,並但願得到更多人的參與和幫助前端

宋寶華: 關於DMA ZONE和dma alloc coherent若干誤解的完全澄清

本文目錄
1.DMA ZONE的大小是16MB?
2.DMA ZONE的內存只能作DMA嗎?
3.dma_alloc_coherent()申請的內存來自DMA ZONE?
4.dma_alloc_coherent()申請的內存是非cache的嗎?
5.dma_alloc_coherent()申請的內存必定是物理連續的嗎?linux

1.DMA ZONE的大小是16MB?

這個答案在32位X86計算機的條件下是成立的,可是在其餘的絕大多數狀況下都不成立。
首先咱們要理解DMA ZONE產生的歷史緣由是什麼。DMA能夠直接在內存和外設之間進行數據搬移,對於內存的存取來說,它和CPU同樣,是一個訪問master,能夠直接訪問內存。
DMA ZONE產生的本質緣由是:不必定全部的DMA均可以訪問到全部的內存,這本質上是硬件的設計限制。git

宋寶華: 關於DMA ZONE和dma alloc coherent若干誤解的完全澄清
在32位X86計算機的條件下,ISA實際只能夠訪問16MB如下的內存。那麼ISA上面假設有個網卡,要DMA,超過16MB以上的內存,它根本就訪問不到。因此Linux內核乾脆簡單一點,把16MB砍一刀,這一刀如下的內存單獨管理。若是ISA的驅動要申請DMA buffer,你帶一個GFP_DMA標記來代表你想從這個區域申請,我保證申請的內存你是能夠訪問的。後端

DMA ZONE的大小,以及DMA ZONE要不要存在,都取決於你實際的硬件是什麼。好比我在CSR工做的時候,CSR的primaII芯片,儘管除SD MMC控制器之外的全部的DMA均可以訪問整個4GB內存,但MMC控制器的DMA只能訪問256MB,咱們就把primaII對應Linux的DMA ZONE設爲了256MB,詳見內核:arch/arm/mach-prima2/common.c架構

#ifdef CONFIG_ARCH_PRIMA2
static const char *const prima2_dt_match[] __initconst = {
        "sirf,prima2",
        NULL
};

DT_MACHINE_START(PRIMA2_DT, "Generic PRIMA2 (Flattened Device Tree)")
        /* Maintainer: Barry Song <baohua.song@csr.com> */
        .l2c_aux_val    = 0,
        .l2c_aux_mask   = ~0,
        .dma_zone_size  = SZ_256M,
        .init_late      = sirfsoc_init_late,
        .dt_compat      = prima2_dt_match,
MACHINE_END
#endif

不過CSR這個公司因爲早前已經被Q記收購,已經再也不存在,一塊兒幻滅的,還有當年掛在汽車前窗上的導航儀。這不由讓我想起咱們當年在ADI arch/blackfin裏面寫的代碼,也漸漸快幾乎沒有人用了同樣。
一代人的芳華已逝,面目全非,重逢雖然談笑如故,可不難看出歲月給每一個人帶來的改變。原諒我不肯讓大家看到咱們老去的樣子,就讓代碼,留住咱們芬芳的年華吧........
宋寶華: 關於DMA ZONE和dma alloc coherent若干誤解的完全澄清app

下面咱們架空歷史,假設有一個以下的芯片,裏面有5個DMA,A、B、C均可以訪問全部內存,D只能訪問32MB,而E只能訪問64MB,你以爲Linux的設計者會把DMA ZONE設置爲多大?固然是32MB,由於若是設置爲64MB,D從DMA ZONE申請的內存就可能位於32MB-64MB之間,申請了它也訪問不了。
宋寶華: 關於DMA ZONE和dma alloc coherent若干誤解的完全澄清
因爲現現在絕大多少的SoC都很牛逼,彷佛DMA都沒有什麼缺陷了,根本就不太可能給咱們機會指定DMA ZONE大小裝逼了,那個這個ZONE就不太須要存在了。反正任何DMA在任何地方申請的內存,這個DMA均可以存取到。ide

2.DMA ZONE的內存只能作DMA嗎?

DMA ZONE的內存作什麼均可以。DMA ZONE的做用是讓有缺陷的DMA對應的外設驅動申請DMA buffer的時候從這個區域申請而已,可是它不是專有的。其餘全部人的內存(包括應用程序和內核)也能夠來自這個區域。.net

3.dma_alloc_coherent()申請的內存來自DMA ZONE?

dma_alloc_coherent()申請的內存來自於哪裏,不是由於它的名字前面帶了個dma_就來自DMA ZONE的,本質上取決於對應的DMA硬件是誰。看代碼:設計

static void *_ _dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
                         gfp_t gfp, pgprot_t prot, bool is_coherent, const void *caller)
{
        u64 mask = get_coherent_dma_mask(dev);
        …

        if (mask < 0xffffffffULL)
                gfp |= GFP_DMA;
                 …
}

對於primaII而言,絕大多少的外設的dma_coherent_mask都設置爲0XffffffffULL(4GB內存全覆蓋),可是SD那個則設置爲256MB-1對應的數字。這樣當primaII的SD驅動調用dma_alloc_coherent()的時候,GFP_DMA標記被設置,以指揮內核從DMA ZONE申請內存。可是,其餘的外設,mask覆蓋了整個4GB,調用dma_alloc_coherent()得到的內存就不須要必定是來自DMA ZONE。

4.dma_alloc_coherent()申請的內存是非cache的嗎?

要解答這個問題,首先要理解什麼叫cache coherent。仍是繼續看這個DMA的圖,咱們假設MEM裏面有一塊紅色的區域,而且CPU讀過它,因而紅色區域也進CACHE:
宋寶華: 關於DMA ZONE和dma alloc coherent若干誤解的完全澄清
可是,假設如今DMA把外設的一個白色搬移到了內存本來紅色的位置:
宋寶華: 關於DMA ZONE和dma alloc coherent若干誤解的完全澄清
這個時候,內存雖然白了,CPU讀到的卻仍是紅色,由於CACHE命中了,這就出現了cache的不coherent。
固然,若是是CPU寫數據到內存,它也只是先寫進cache(不必定進了內存),這個時候若是作一個內存到外設的DMA操做,外設可能就獲得錯誤的內存裏面的老數據。
因此cache coherent的最簡單方法,天然是讓CPU訪問DMA buffer的時候也不帶cache。事實上,缺省狀況下,dma_alloc_coherent()申請的內存缺省是進行uncache配置的。
可是,因爲現代SoC特別強,這樣有一些SoC裏面能夠用硬件作CPU和外設的cache coherence,如圖中的cache coherent interconnect:
宋寶華: 關於DMA ZONE和dma alloc coherent若干誤解的完全澄清
這些SoC的廠商就能夠把內核的通用實現overwrite掉,變成dma_alloc_coherent()申請的內存也是能夠帶cache的。這部分仍是讓大牛Arnd Bergmann童鞋來解釋:


來自:https://www.spinics.net/lists/arm-kernel/msg322447.html
Arnd Bergmann:
dma_alloc_coherent() is a wrapper around a device-specific allocator,
based on the dma_map_ops implementation. The default allocator
from arm_dma_ops gives you uncached, buffered memory. It is expected
that the driver uses a barrier (which is implied by readl/writel
but not __raw_readl/__raw_writel or readl_relaxed/writel_relaxed)
to ensure the write buffers are flushed.

If the machine sets arm_coherent_dma_ops rather than arm_dma_ops,
the memory will be cacheable, as it's assumed that the hardware
is set up for cache-coherent DMAs.


當我grep內核源代碼的時候,我發現部分SoC確實是這樣實現的:


baohua@baohua-VirtualBox:~/develop/linux/arch/arm$ git grep arm_coherent_dma_ops
include/asm/dma-mapping.h:extern struct dma_map_ops arm_coherent_dma_ops;
mach-highbank/highbank.c: set_dma_ops(dev, &arm_coherent_dma_ops);
mach-mvebu/coherency.c: set_dma_ops(dev, &arm_coherent_dma_ops);


5.dma_alloc_coherent()申請的內存必定是物理連續的嗎?

絕大多數的SoC目前都支持和使用CMA技術,而且多數狀況下,DMA coherent APIs以CMA區域爲申請的後端,這個時候,dma alloc coherent本質上用_ _alloc_from_contiguous()從CMA區域獲取內存,申請出來的內存顯然是物理連續的。這一點,在設備樹dts裏面就能夠輕鬆配置,要麼配置一個本身特定的cma區域,要麼從「linux,cma-default」指定的缺省的CMA池子裏面取內存:

reserved-memory {
                #address-cells = <1>;
                #size-cells = <1>;
                ranges;

                /* global autoconfigured region for contiguous allocations */
                linux,cma {
                        compatible = "shared-dma-pool";
                        reusable;
                        size = <0x4000000>;
                        alignment = <0x2000>;
                        linux,cma-default;
                };

                display_reserved: framebuffer@78000000 {
                        reg = <0x78000000 0x800000>;
                };

                multimedia_reserved: multimedia@77000000 {
                        compatible = "acme,multimedia-memory";
                        reg = <0x77000000 0x4000000>;
                };
        };

可是,若是IOMMU存在(ARM裏面叫SMMU)的話,DMA徹底能夠訪問非連續的內存,而且把物理上不連續的內存,用IOMMU進行從新映射爲I/O virtual address (IOVA):
宋寶華: 關於DMA ZONE和dma alloc coherent若干誤解的完全澄清
因此dma_alloc_coherent()這個API只是一個前端的界面,它的內存究竟從哪裏來,究竟要不要連續,帶不帶cache,都徹底是因人而異的。

最後總結一句,千萬不要被教科書和各類網上的資料懵逼了雙眼,你必定要真正本身探索和搞清楚事情的本源。今天看了《芳華》這部電影,感慨良多,遂做此文。

相關文章
相關標籤/搜索