dts中memreserve和reserved-memory的區別

Devicetree 提供了兩種方式預留內存: reserved-memory和memreserve

memreserve示例

/memreserve/ 0x40000000 0x01000000

reserved-memory示例

    reserved-memory {
        #address-cells = <1>;
        #size-cells = <1>;
        ranges;
 
        ipu_cma@90000000 {
            compatible = "shared-dma-pool";
            reg = <0x90000000 0x4000000>;
            reusable;
            status = "okay";
        };


區別1:
二者在dtc編譯時中處理的方法不同, reserved-memory做爲device tree node解析到device-tree structure中; memreserve最終會加到dtb文件的memory reserve map,

見下圖

區別2
二者在內核中的處理方式不同

1 memreserve處理流程
start_kernel                                                               - init/main.c

    ->setup_arch                                                        - arch/arm/kernel/setup.c

        ->arm_memblock_init                                      - arch/arm/kernel/setup.c

            ->arm_dt_memblock_reserve                    - arch/arm/kernel/devtree.c

arm_dt_memblock_reserve實現如下

   

/* Reserve the dtb region */
    memblock_reserve(virt_to_phys(initial_boot_params),
             be32_to_cpu(initial_boot_params->totalsize));
 
    /*
     * Process the reserve map.  This will probably overlap the initrd
     * and dtb locations which are already reserved, but overlaping
     * doesn't hurt anything
     */
    reserve_map = ((void*)initial_boot_params) +
            be32_to_cpu(initial_boot_params->off_mem_rsvmap);
    while (1) {
        base = be64_to_cpup(reserve_map++);
        size = be64_to_cpup(reserve_map++);
        if (!size)
            break;
        memblock_reserve(base, size);
    }


initial_boot_params實際指向dtb文件在內存中的位置, 該地址還可以指向其他類型的啓動參數

initial_boot_params頭中的off_mem_rsvmap指向一系列的reserve memory(地址, 尺寸)空間, 對於dtb來說, 就是memory reserve map.

2 reserved-memory處理流程
start_kernel                                                                  - init/main.c

    ->setup_arch                                                           - arch/arm/kernel/setup.c

        ->arm_memblock_init                                          - arch/arm/kernel/setup.c

            ->early_init_fdt_scan_reserved_mem           - arch/arm/mm/init.c
                ->__fdt_scan_reserved_mem,                   - drivers/of/fdt.c

                    ->__reserved_mem_reserve_reg          - drivers/of/fdt.c

                        ->early_init_dt_reserve_memory_arch     - drivers/of/fdt.c

                            ->memblock_remove                              - mm/memblock.c

                            ->memblock_reserve                              - mm/memblock.c

            ->fdt_init_reserved_mem

reserved-memory有一些可選參數, 比如no-map, 如果使用了no-map, 那麼這段區域執行memblock_remove, 反之執行memblock_reserve.

在調用完memblock_reserve後,還會執行fdt_init_reserved_mem

void __init fdt_init_reserved_mem(void)
{
         ...
        if (rmem->size == 0)
            err = __reserved_mem_alloc_size(node, rmem->name,
                         &rmem->base, &rmem->size);
        if (err == 0)
            __reserved_mem_init_node(rmem);
        ...
}

/** 
 * res_mem_init_node() - call region specific reserved memory init code
 */ 
static int __init __reserved_mem_init_node(struct reserved_mem *rmem)
{
    ...
    
    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))
            continue;
        if (initfn(rmem) == 0) {
            pr_info("Reserved memory: initialized node %s, compatible id %s\n",
                rmem->name, compat);
            return 0;
        }
    }
    return -ENOENT;
}


如果reserved-memory下節點的compatible=<shared-dma-pool>, 則這塊內存會被用來進行Contiguous Memory Allocator for dma

initfn對應drivers/base/dma-contiguous.c下的rmem_cma_setup以及drivers/base/dma-coherent.c中的rmem_dma_setup, 由於二者的compatible相同,所以前者優先.

rmem_cma_setup會對這塊內存做初始化,  把這塊區域加到cma_areas[cma_area_count]中

cma_areas保存着所有的CMA區域, 稍後core_init_reserved_areas會對這個數組進行處理

static int __init cma_init_reserved_areas(void)
{
    int i;
 
    for (i = 0; i < cma_area_count; i++) {
        int ret = cma_activate_area(&cma_areas[i]);
        if (ret)
            return ret;
    }
 
    return 0;
}
core_initcall(cma_init_reserved_areas);


cma_activate_area把該cma area中的所有pages都改爲MIGRATE_CMA, 並加到MIGRATE_CMA的free_list上.

區別3
由於二者的處理流程不同, 導致memreserve分配的內存, 無法再被操作系統使用; 而reserved-memory內存有可能進入系統CMA, 是否做爲CMA, 依賴以下幾個條件:

1. compatible 必須爲shared-dma-pool

2. 沒有定義no-map屬性

3. 定義了resuable屬性

原文鏈接:https://blog.csdn.net/kickxxx/article/details/54631535

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章