【问题标题】:How to work with reserved CMA memory?如何使用保留的 CMA 内存?
【发布时间】:2016-02-22 14:48:03
【问题描述】:

我想为支持 DMA 的设备分配一块物理上连续的保留内存(在预定义的物理地址中)。 正如我所见,CMA 有三个选项: 1. 通过内核配置文件保留内存。 2. 通过内核命令行预留内存。 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 次,最多可以分配 8M。不过很遗憾

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)

不可能为连续分配设置预定义的物理地址。 当然我可以使用内核命令行:

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

并在某个节点中进行 phandle:

memory-region = <&cmadev_region>;

正如我在内核中看到的那样,它应该像这样使用:

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.

但我想通过 dma_alloc_coherent() 代替 IO-MAP ioremap() 使用 DMA(因为我只知道一个外部 API 函数 dma_alloc_coherent)。但是怎么调用

start_cma_virt = dma_alloc_coherent(dev->cmadev, (size_t)size_cma, &start_cma_dma, GFP_KERNEL);

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

【问题讨论】:

    标签: memory-management linux-kernel linux-device-driver virtual-memory device-tree


    【解决方案1】:

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

    在 dt 中:

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

    现在您可以在这个 cma_dev 上执行 dma_alloc_coherent 并获取内存。

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关其解决问题的方式和/或原因的附加上下文将提高​​答案的长期价值。Read this
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-11
    • 2021-06-05
    • 2023-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多