一.CMA相关的宏
RESERVEDMEM_OF_DECLARE(cma, "shared-dma-pool", rmem_cma_setup);
#define RESERVEDMEM_OF_DECLARE(name, compat, init) \
_OF_DECLARE(reservedmem, name, compat, init, reservedmem_of_init_fn)
/// __reservedmem_of_table __of_table_cma
#if defined(CONFIG_OF) && !defined(MODULE)
#define _OF_DECLARE(table, name, compat, fn, fn_type) \
static const struct of_device_id __of_table_##name \
__used __section(__##table##_of_table) \
= { .compatible = compat, \
.data = (fn == (fn_type)NULL) ? fn : fn }
#else
#define _OF_DECLARE(table, name, compat, fn, fn_type) \
static const struct of_device_id __of_table_##name \
__attribute__((unused)) \
= { .compatible = compat, \
.data = (fn == (fn_type)NULL) ? fn : fn }
#endif
1.1一般内存的初始化化
setup_arch--->setup_machine_fdt--->early_init_dt_scan--->early_init_dt_scan_nodes--->early_init_dt_add_memory_arch--->memblock_add
1.2 reserved-memory
init.c arm_memblock_init()
fdt.c ----early_init_fdt_reserve_self();
----early_init_fdt_scan_reserved_mem()
__fdt_scan_reserved_mem // of_reserved_mem.c
__reserved_mem_reserve_reg
|-----early_init_dt_reserve_memory_arch
|-----fdt_reserved_mem_save_node 在这个函数中,reserved-mem节
点下的子节点会解析出来,保存到数组//reserved_mem[reserved_mem_count]中,保存完后,
reserved_mem_count增加。
fdt_init_reserved_mem() // of_reserved_mem.c,遍历数组reserved_mem
|----struct reserved_mem *rmem = &reserved_mem[i];
__reserved_mem_alloc_size
__reserved_mem_init_node()//在遍历的过程中,每个数组成员比对compatible是否是"shared-dma-pool",
如果是,则执行rmem_cma_setup,初始化该块CMA
----dma_contiguous_reserve(arm_dma_limit);//cmdline的配置
1.3 device tree example
一下示例来自于内核文档reserved-memory.txt
/ {
#address-cells = <1>;
#size-cells = <1>;
memory {
reg = <0x40000000 0x40000000>;
};
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 {
compatible = "shared-dma-pool";
reg = <0x78000000 0x800000>;
};
multimedia_reserved: multimedia@77000000 {
compatible = "acme,multimedia-memory";
reg = <0x77000000 0x4000000>;
};
};
/* ... */
fb0: video@12300000 {
memory-region = <&display_reserved>;
/* ... */
};
scaler: scaler@12500000 {
memory-region = <&multimedia_reserved>;
/* ... */
};
codec: codec@12600000 {
memory-region = <&multimedia_reserved>;
/* ... */
};
};
二.各个具体的设备初始化并且使用固定一块的reserved_mem
static int codec_mm_probe(struct platform_device *pdev)
{
int r;
pdev->dev.platform_data = get_mem_mgt();
r = of_reserved_mem_device_init(&pdev->dev); //根据memory-region来找到某个dma块
if (r == 0)
pr_debug("codec_mm_probe mem init done\n");
}
static inline int of_reserved_mem_device_init(struct device *dev)
{
return of_reserved_mem_device_init_by_idx(dev, dev->of_node, 0);
}
int of_reserved_mem_device_init_by_idx(struct device *dev, struct device_node *np, int idx)
{
target = of_parse_phandle(np, "memory-region", idx);
}
三.通过 bootarg来配置CMA
Cmdline指定:
在bootargs可以添加cma属性指定cma区域,如下所示:
Bootargs=”cma=0x40000@0x70000000-0x80000000”
其中0x400000是大小,0x70000000-0x80000000指定cma的分配区间。
a) drivers/base/dma-contiguous.c文件中,
early_param("cma", early_cma) 解析bootargs的cmd参数,并将cma的大小赋值给size_cmdline,cma的起始地址赋值给base_cmdline,cma的结束地址赋值给limit_cmdline。
b) arch/arm/kernel/setup.c 文件中,
setup_arch
arm_memblock_init
dma_contiguous_reserve
在dma_contiguos_reserve过程中会将size,base和limit对齐4M,dma_contiguous_default_area。