"removed-dma-pool" and "shared-dma-pool"

作者 by adtxl / 2022-11-10 / 暂无评论 / 47 个足迹

内核版本:Android common kernel 4.19.176





Additional properties:
compatible (optional) - standard definition
    - may contain the following strings:
        - shared-dma-pool: This indicates a region of memory meant to be
          used as a shared pool of DMA buffers for a set of devices. It can
          be used by an operating system to instanciate the necessary pool
          management subsystem if necessary.
    - removed-dma-pool: This indicates a region of memory which is meant to
      be carved out and not exposed to kernel.
        - vendor specific string in the form <vendor>,[<device>-]<usage>
no-map (optional) - empty property
    - Indicates the operating system must not create a virtual mapping
      of the region as part of its standard mapping of system memory,
      nor permit speculative access to it under any circumstances other
      than under the control of the device driver using the region.
no-map-fixup (optional) - empty property
    - Indicates the operating system must reserve the memory region and keep
      virtual mapping. Upon first allocation the actual allocated region is
      removed for any virtual mapping and behaves as "no-map" while the
      remaining memory is returned back to the system for normal use. One would
      like to use this property where he is not sure about how much region size
      must be reserved, so he gives it a max size which then is shrink once
      (first) allocation is done. This property is for some specific use cases,
      if unsure please don't use it. This property cannot be used together with
      "no-map" attribute.
reusable (optional) - empty property
    - The operating system can use the memory in this region with the
      limitation that the device driver(s) owning the region need to be
      able to reclaim it back. Typically that means that the operating
      system can use that region to store volatile or cached data that
      can be otherwise regenerated or migrated elsewhere.


    xxx_reserved: memory@xxx00000 {
            reg = <0 0xxx00000 0 0x400000>;
            compatible = "shared-dma-pool";
// 或者类似下面这样,定义一块默认的cma内存
        /* global autoconfigured region for contiguous allocations */
        linux,cma {
            compatible = "shared-dma-pool";
            size = <0x00000000 0x08000000>;


xxx_reserved: memory@e6c00000 {
            reg = <0 0xe6c00000 0 0x01000000>;
            compatible = "shared-dma-pool";


根据/proc/iomem文件节点内容,这段内存既属于system ram,也是reserved-memory

cat /proc/iomem
e6600000-e66fffff : System RAM
  e6600000-e66fffff : reserved
e6c00000-ffffffff : System RAM
  e6c00000-e7bfffff : reserved

2. 记录系统预留内存



在kernel初始化阶段,通过调用start_kernel()->setup_arch()->arm64_memblock_init()->early_init_fdt_scan_reserved_mem()->fdt_init_reserved_mem()->__reserved_mem_init_node()完成对reserved memory的创建和初始化:

 * res_mem_init_node() - call region specific reserved memory init code
static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
    extern const struct of_device_id __reservedmem_of_table[];
    const struct of_device_id *i;
    // __reservedmem_of_table是初始化中的一个section段,通过RESERVEDMEM_OF_DECLARE定义的都会被链接到这个段中
    for (i = __reservedmem_of_table; i < &__rmem_of_table_sentinel; i++) {
        reservedmem_of_init_fn initfn = i->data;
        const char *compat = i->compatible;

        if (!of_flat_dt_is_compatible(rmem->fdt_node, compat))
        // 这里实际运行上面注册的回调
        if (initfn(rmem) == 0) {
            pr_info("initialized node %s, compatible id %s\n",
                rmem->name, compat);
            return 0;
    return -ENOENT;

3. 区域的创建


3.1 removed_dma_setup


static int rmem_dma_device_init(struct reserved_mem *rmem, struct device *dev)
    struct removed_region *mem = rmem->priv;

    if (!mem && dma_init_removed_memory(rmem->base, rmem->size, &mem)) {
        pr_info("Reserved memory: failed to init DMA memory pool at %pa, size %ld MiB\n",
            &rmem->base, (unsigned long)rmem->size / SZ_1M);
        return -EINVAL;
    set_dma_ops(dev, &removed_dma_ops);
    rmem->priv = mem;
    dma_assign_removed_region(dev, mem);
    return 0;

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

static const struct reserved_mem_ops removed_mem_ops = {
    .device_init    = rmem_dma_device_init,
    .device_release = rmem_dma_device_release,

static int __init removed_dma_setup(struct reserved_mem *rmem)
    rmem->ops = &removed_mem_ops;
    pr_info("Removed memory: created DMA memory pool at %pa, size %ld MiB\n",
        &rmem->base, (unsigned long)rmem->size / SZ_1M);
    return 0;

3.2 rmem_cma_setup


static int rmem_cma_device_init(struct reserved_mem *rmem, struct device *dev)
    dev_set_cma_area(dev, rmem->priv);
    return 0;

static void rmem_cma_device_release(struct reserved_mem *rmem,
                    struct device *dev)
    dev_set_cma_area(dev, NULL);

static const struct reserved_mem_ops rmem_cma_ops = {
    .device_init    = rmem_cma_device_init,
    .device_release = rmem_cma_device_release,

static int __init rmem_cma_setup(struct reserved_mem *rmem)
    phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1, pageblock_order);
    phys_addr_t mask = align - 1;
    unsigned long node = rmem->fdt_node;
    struct cma *cma;
    int err;

    if (!of_get_flat_dt_prop(node, "reusable", NULL) ||
        of_get_flat_dt_prop(node, "no-map", NULL))
        return -EINVAL;

    if ((rmem->base & mask) || (rmem->size & mask)) {
        pr_err("Reserved memory: incorrect alignment of CMA region\n");
        return -EINVAL;

    err = cma_init_reserved_mem(rmem->base, rmem->size, 0, rmem->name, &cma);
    if (err) {
        pr_err("Reserved memory: unable to setup CMA region\n");
        return err;
    /* Architecture specific contiguous memory fixup. */
    dma_contiguous_early_fixup(rmem->base, rmem->size);

    if (of_get_flat_dt_prop(node, "linux,cma-default", NULL))

    rmem->ops = &rmem_cma_ops;
    rmem->priv = cma;

    pr_info("Reserved memory: created CMA memory pool at %pa, size %ld MiB\n",
        &rmem->base, (unsigned long)rmem->size / SZ_1M);

    return 0;

3.3 rmem_dma_setup


xxx_reserved: memory@e6c00000 {
            reg = <0 0xe6c00000 0 0x01000000>;
            compatible = "shared-dma-pool";


static int __init rmem_dma_setup(struct reserved_mem *rmem)
    unsigned long node = rmem->fdt_node;

    if (of_get_flat_dt_prop(node, "reusable", NULL))
        return -EINVAL;

    if (!of_get_flat_dt_prop(node, "no-map", NULL)) {
        pr_err("Reserved memory: regions without no-map are not yet supported\n");
        return -EINVAL;

    if (of_get_flat_dt_prop(node, "linux,dma-default", NULL)) {
             "Reserved memory: region for default DMA coherent area is redefined\n");
        dma_reserved_default_memory = rmem;

    rmem->ops = &rmem_dma_ops;
    pr_info("Reserved memory: created DMA memory pool at %pa, size %ld MiB\n",
        &rmem->base, (unsigned long)rmem->size / SZ_1M);
    return 0;