先解释下cma
CMA,Contiguous Memory Allocator,是内存管理中的一个模块,用于分配连续物理内存。
主要是针对多媒体,camera这种需要分配大段连续物理内存的模块使用(camera需要用到dma,dma正常只支持物理连续内存搬运)。
Cma还可以与dma子系统继承在一起,使用dma的设备驱动只需要访问dma相关api即可。

先看下cma结构体
用于描述一个cma

struct cma {
	unsigned long   base_pfn;//物理地址起始页帧号
	unsigned long   count;     //总页数
//描述分页情况 0:free 1:已分配,里面的每个bit对应后面order_per_bit表示个数的分配情况
	unsigned long   *bitmap; 
	//以order_per_bit 的2次方个page为单位申请释放
	unsigned int order_per_bit; /* Order of pages represented by one bit */
	struct mutex    lock;
#ifdef CONFIG_CMA_DEBUGFS
	struct hlist_head mem_head;
	spinlock_t mem_head_lock;
#endif
};
//描述所有的cma数组
 extern struct cma cma_areas[MAX_CMA_AREAS];
 #ifdef CONFIG_CMA_AREAS
 #define MAX_CMA_AREAS (1 + CONFIG_CMA_AREAS)
 Rk定义的CONFIG_CMA_AREAS=7

为了更好的理解结构体来个例子:

base_pfn 假如页码为0x400,count 为0x20

那么占用内存的页为0x400-0x420

order_per_bit为1表示以2页为申请和释放的单位

bitmap的第0bit为1,表示0x400和0x401页被分配,根据总页数除以order_per_bit可以得到需要占用的bit数,bit数再除long型所占用的bit数,就得出bitmap需要分配多少个long的空间。

cma架构和bma架构_cma架构和bma架构


RESERVEDMEM_OF_DECLARE(cma, “shared-dma-pool”, rmem_cma_setup);

早期rk是通过rmem_cma_setup函数来配置初始化cma内存,现在已经弃用就不再分析。

cma架构和bma架构_内存管理_02


现在是通过内核宏的方式配置,那调用情况如下

在init.c
 void __init arm64_memblock_init(void)中会调用dma_contiguous_reserve(arm64_dma_phys_limit);申请预留内存
 dma_contiguous_reserve_area
 cma_declare_contiguous
 memblock_alloc_range 用memblock进行区域分配,如果想再往下看怎么分配还可以继续,留作以看,memblock是kernel早期的内存分配器,分配完了之后需要初始化
 core_initcall(cma_init_reserved_areas);
 cma_init_reserved_areas函数
 cma_activate_area
 这个函数主要是先分配bitmap的空间,前面有说到原理。
 然后调用page_zone,获取所在的zone ,page zone又是一个概念,也先记着
 主要工作是最后调用
 init_cma_reserved_pageblock(pfn_to_page(base_pfn));
 里面先调用set_pageblock_migratetype(page, MIGRATE_CMA);设置page的cma标志。__free_pages,将内存释放到伙伴系统中。Buddy system内存管理可以去了解。
 最后adjust_managed_page_count 调整zoon管理的页面总数,因为分配连续内存要在一个zoon里。函数主要功能就是将内存加入伙伴系统,方便其他应用可以通过伙伴系统分配内存。
cma_alloc和cma_release分别是cma的申请和释放函数
 通过和dma子系统绑定
 dma_alloc_from_contiguous
 dma_release_from_contiguous 分别调用cma的分配和释放函数
 其实dma-contiguous.c里面全部的cma的操作,应用可以使用dma分配连续内存,不用关心底层分配情况。看到最终,rk3399 camera模块并没有用到cma。Rkisp使用了iommu之后,就没有使用预留内存。
 既然了解了dma-contiguous.c那么dma-coherent.c也了解一下
 Rk camera也没有用到这个,说下个人的理解。
 这个是针对各个device预留的空间,在dts中已经有相关预留参数。所以dts没有的是使用不了这个接口。
 在代码中可以调用of_reserved_mem_device_init获取预留内存的相关信息
 解析关键字memory-region,获取并初始化后, 各个device可以使用coherent相关的接口去获取和使用内存。

最后查找,实际使用的是dma-mapping.c,这个用于内存和iommu转换。