Memory management 如何使用保留的CMA内存?

Memory management 如何使用保留的CMA内存?,memory-management,linux-kernel,linux-device-driver,virtual-memory,device-tree,Memory Management,Linux Kernel,Linux Device Driver,Virtual Memory,Device Tree,我想为支持DMA的设备分配一块物理上连续的保留内存(在预定义的物理地址中)。 正如我所见,CMA有三种选择: 1.通过内核配置文件保留内存。2.通过内核cmdline保留内存。3.通过设备树内存节点保留内存。 在第一种情况下:可以保留区域的大小和数量 CONFIG_DMA_CMA=y CONFIG_CMA_AREAS=7 CONFIG_CMA_SIZE_MBYTES=8 所以我可以用: start_cma_virt = dma_alloc_coherent(dev->cmadev, (s

我想为支持DMA的设备分配一块物理上连续的保留内存(在预定义的物理地址中)。 正如我所见,CMA有三种选择: 1.通过内核配置文件保留内存。2.通过内核cmdline保留内存。3.通过设备树内存节点保留内存。 在第一种情况下:可以保留区域的大小和数量

CONFIG_DMA_CMA=y
CONFIG_CMA_AREAS=7
CONFIG_CMA_SIZE_MBYTES=8
所以我可以用:

start_cma_virt = dma_alloc_coherent(dev->cmadev, (size_t)size_cma, &start_cma_dma, GFP_KERNEL);
在我的驱动程序中分配连续内存。我最多可以使用7次,最多可以分配800万次。但不幸的是

dma_contiguous_reserve(min(arm_dma_limit, arm_lowmem_limit));
从arch/arm/mm/init.c开始:

void __init arm_memblock_init(struct meminfo *mi,const struct machine_desc *mdesc)
无法为连续分配设置预定义的物理地址。 当然,我可以使用内核cmdline:

mem=cma=cmadevlabel=8M@32M cma_map=mydevname=cmadevlabel
//struct device *dev = cmadev->dev; /*dev->name is mydevname*/
在此之后,dma_alloc_coherent()应将物理内存区域中的内存从32M+8M(0x2000000+0x800000)分配到0x27FFFFF。 但不幸的是,我对这个解决方案有问题。也许我的命令行有错误? 下一个尝试是设备树实现

cmadev_region: mycma {
    /*no-map;*/ /*DMA coherent memory*/
    /*reusable;*/
    reg = <0x02000000 0x00100000>;      
};
但我想使用DMA via(因为我只知道一个外部API函数DMA_alloc_coherent)DMA_alloc_coherent()代替IO-MAP ioremap()。但是怎么打电话呢

start\u cma\u virt=dma\u alloc\u相干(dev->cmadev,(size\t)size\u cma和start\u cma\u dma,GFP\u内核)

将内存从设备树(reg=;)关联到dev->cmadev?在使用cmdline的情况下,很明显它具有设备名称和地址区域。 调用_parse_phandle()后是否应该为您的特殊驱动程序(解析DT)自动预订保留内存。下一个调用dma_alloc_coherent将从cmadev_区域分配内存中的dma区域:mycma

要在保留内存节点上使用dma_alloc_coherent(),需要将该区域声明为dma_coherent。您可以执行以下操作:

在dt中:

cmadev_region: mycma {
    compatible = "compatible-name"
    no-map;
    reg = <0x02000000 0x00100000>;      
};

现在,在这个cma_dev上,您可以执行dma_alloc_连贯并获得内存。

虽然这段代码可能会回答这个问题,但提供有关如何和/或为什么解决问题的额外上下文将提高答案的长期价值。。
of_find_node_by_name(); //find needed node
of_parse_phandle(); //resolve a phandle property to a device_node pointer
of_get_address(); //get DT __be32 physical addresses
of_translate_address(); //DT represent local (bus, device) addresses so translate it to CPU physical addresses 
request_mem_region(); //reserve IOMAP memory (cat /proc/iomem)
ioremap(); //alloc entry in page table for reserved memory and return kernel logical addresses.
cmadev_region: mycma {
    compatible = "compatible-name"
    no-map;
    reg = <0x02000000 0x00100000>;      
};
struct device *cma_dev;

static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
{
    int ret;

    if (!mem) {
        ret = dma_declare_coherent_memory(cma_dev, rmem->base, rmem->base,
                           rmem->size, DMA_MEMORY_EXCLUSIVE);
        if (ret) {
            pr_err("Error");
            return ret;
        }
    }
    return 0;
}

static void rmem_dma_device_release(struct reserved_mem *rmem,
                struct device *dev)
{
    if (dev)
        dev->dma_mem = NULL;
}

static const struct reserved_mem_ops rmem_dma_ops = {
    .device_init    = rmem_dma_device_init,
    .device_release = rmem_dma_device_release,
};

int __init cma_setup(struct reserved_mem *rmem)
{
    rmem->ops = &rmem_dma_ops;
    return 0;
}
RESERVEDMEM_OF_DECLARE(some-name, "compatible-name", cma_setup);