一,设置cma空间(大小和地址等)
CONFIG_CMA=y
CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=64
配置CONFIG_CMA=y
后,cma空间应默认为64M.
如果需要修改,先配置CONFIG_DMA_CMA=y
打开DMA Contiguous Memory Allocator, 再配置CONFIG_CMA_SIZE_MBYTES
大小就行。
二,关键数据
1,dma_mask与coherent_dma_mask
coherent_dma_mask :用来分配连续一致性dma。
dma_mask:在dma_map_single->dma_map_page,dma_capable用。
dev->coherent_dma_mask = 0xffffffffUL;//默认设置4G
dma_mask与coherent_dma_mask这两个参数表示它能寻址的物理地址的范围,内核通过这两个参数分配合适的物理内存给 device。其中dma_coherent_mask则作用于申请一致性DMA缓冲区。因为不是所有的硬件都能够支持64bit的地址宽度。如果 addr_phy 是一个物理地址,且 (u64)addr_phy <= *dev->dma_mask,那么 该 device 就可以寻址该物理地址。如果 device 只能寻址32位地址,那么 mask 应为 0xffffffff。依此类推。
2,dma_range_map是用于设置DMA内存映射配置
of_dma_configure_id中ret = of_dma_get_range(np, &map);
if (ret > 0)
{
dev->dma_range_map = map;
}
地址转换
if (dev->dma_range_map)
return translate_phys_to_dma(dev, paddr);
if (dev->dma_range_map)
paddr = translate_dma_to_phys(dev, dma_addr);
3,cma_area和dma_contiguous_default_area
static inline struct cma *dev_get_cma_area(struct device *dev)
{
if (dev && dev->cma_area)
return dev->cma_area;//设备自己的cma_area
return dma_contiguous_default_area;
}
默认cma创建(dma_contiguous_default_area),两种方式:
1,通过cmdline传递的参数"cma=",然后在kernel初始化阶段解析参数,并调用start_kernel()->setup_arch()->arm64_memblock_init()->dma_contiguous_reserve()完成创建
2,通过dts中配置cma节点,属性中包含"shared-dma-pool"以及"linux,cma-default",在kernel初始化阶段,通过调用start_kernel()->setup_arch()->arm64_memblock_init()->early_init_fdt_scan_reserved_mem()->fdt_init_reserved_mem()->__reserved_mem_init_node()完成对默认cma的创建和初始化
三,代码使用cma的配置
reserved-memory节点配置
linux,cma {
compatible = "shared-dma-pool";
reusable;
reg = <0x0 0x02800000 0x0 0x12c00000>; //300M
linux,cma-default;
};
驱动rkisp1_plat_probe函数调用
dev->archdata.dma_coherent = true;
dev->dma_coherent = true;
dev->coherent_dma_mask = 0xffffffffUL;//默认设置4G
of_dma_configure(dev, dev->of_node, false);
rkisp1节点不配置dma-ranges,使dev->dma_range_map=NULL;