DMA内存大小、连续性、cache一致性、如何配置CMA的总结

1、DMA ZONE的大小只能是16M ?

这个答案在32位X86计算机的条件下是成立的,但是在其他的绝大多数情况下都不成立。

首先我们要理解DMA ZONE产生的历史原因是什么。DMA可以直接在内存和外设之间进行数据搬移,对于内存的存取来讲,它和CPU一样,是一个访问master,可以直接访问内存。

DMA ZONE产生的本质原因是:不一定所有的DMA都可以访问到所有的内存,这本质上是硬件的设计限制。牛B的DMA引擎是访问内存范围是没有限制的,就可以不用DMA ZONE的内存,可以不使用GPF_DMA标志。

在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 。

这个在配置 你的DMA设备的时候要配置你DMA引擎可以访问到的内存,比如申请dma内存的接口  dma_alloc_coherent()申请的内存来自DMA ZONE 也不一定来自 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。

2、DMA ZONE 只能做DMA 内存吗?

DMA ZONE的内存做什么都可以。DMA ZONE的作用是让有缺陷的DMA对应的外设驱动申请DMA buffer的时候从这个区域申请而已,但是它不是专有的。其他所有人的内存(包括应用程序和内核)也可以来自这个区域。

3、如何保证 DMA 和 cache的一致性?dma_alloc_coherent()申请的内存是非cache的吗?申请DMA内存有几种接口?

回答请参考 :dma 和 cache的一致性

4、dma_alloc_coherent()申请的内存一定是物理连续的吗?

绝大多数的SoC目前都支持和使用CMA技术,并且多数情况下,DMA coherent APIs以CMA区域为申请的后端,

这个时候,dma alloc coherent本质上用__alloc_from_contiguous()从CMA区域获取内存,申请出来的内存显然是物理连续的。

这一点,在设备树dts里面就可以轻松配置,要么配置一个自己特定的cma区域,要么从“linux,cma-default”指定的缺省的CMA池子里面取内存。

但是,针对有MMU的DMA引擎,dma_alloc_coherent 申请的物理地址是可以不连续的,MMU会将不连续的物理地址,转化为连续的虚拟地址给DMA使用。

另外,支持聚集散列的DMA引擎,物理地址也是可以不连续的,不过要采用流式映射的 dma_map_sg 来处理cache一致性的问题。

5、关于如何配置memory节点,如何配置CMA节点?

可以参考下面的官方文档:

https://buildmedia.readthedocs.org/media/pdf/devicetree-specification/latest/devicetree-specification.pdf

  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>;
                };
        };

注意:这里重复 一下下面的区别。

                #address-cells = <1>;   # reg的地址需要一个 u32 位的数字表示
                #size-cells = <0>;   # 地址的长度 需要0个 u32 位的数字表示,就是不需要

cpus {
        #address-cells = <1>;
        #size-cells = <0>;
        cpu@0 {
            compatible = "arm,cortex-a9";
            reg = <0>;
        };
        cpu@1 {
            compatible = "arm,cortex-a9";
            reg = <1>;
        };
    };

                #address-cells = <1>; # reg的地址需要一个 u32 位的数字表示
                #size-cells = <1>;   # 地址的长度 需要1个 u32 位的数字表示

uart{
    #address-cells = <1>;
    #size-cells = <1>;
 
    ...
 
    serial@101f0000 {
        compatible = "arm,pl011";
        reg = <0x101f0000 0x1000 >;
    };
}

                #address-cells = <2>; # reg的地址需要2个 u32 位的数字表示
                #size-cells = <2>;  # 地址的长度 需要2个 u32 位的数字表示

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值