基于msm-5.4
关键词 cma_alloc/cma_release MIGRATE_ISOLATE MIGRATE_CMA
一、概述
1. CMA简介
CMA(Contiguous Memory Alloctor)主要用于分配大块连续的物理内存。伙伴系统能分配的最大连续物理内存块是2^10,即一个pageblock大小4MB。为了提高内存的使用率,嵌入式平台上一般使用CMA.。
在伙伴系统的 free_area[] 链表中有一个 MIGRATE_CMA 类型,当不需要分配大块连续物理内存时,会将CMA内存通过伙伴系统提供给其它模块使用。
和DMA功能类似,CMA也是预先预留出一块连续的物理内存,给多媒体等需要大块连续物理内存的模块使用,如果不使用,CMA内存区也不会空闲着,通过伙伴系统的 free_page()/alloc_pages() 接口释放到伙伴系统,给其它模块使用。
当需要大块连续物理内存时,才会从CMA中分配,当CMA内存不足时,会将其释放到伙伴系统中的内存再拿回来,若属于CMA的一些页面已经被其它程序使用了,那么还要做一个迁移操作,腾出连续的区域。
简化理解,CMA区域就是对DMA区域的改进,在不使用时不让其空闲着,释放给伙伴系统给其它程序使用,当需要使用时再收回来,一方面满足了分配大块连续物理内存的需求,另一方面提高了内存的使用率。
2. CMA对外接口
cma_alloc(): 从CMA区域分配一大块连续的物理内存,若此内存已经被伙伴系统给别人使用了,还要回收回来用作CMA内存使用。
cma_release(): 当使用完CMA内存时,调用此函数将内存返还给CMA,CMA会调用伙伴系统的 free_page() 将这块内存释放到伙伴系统中,供其它模块使用。
实际上驱动很少通过 cma_alloc()/cma_release() 接口去分配CMA内存了,主要是通过DMA接口间接调用到CMA接口。
3. CMA实现
//mm/cma.h struct cma { unsigned long base_pfn; //此CMA区域起始页帧号 unsigned long count; //物理页的个数 unsigned long *bitmap; //表示此CMA中物理页的使用情况,每一个bit位表示一个物理页是否被分出去了还是空闲的。 unsigned int order_per_bit; //和上面bitmap配合使用,若为0则每个bit代表一个物理页,若为1则表示每个bit代表两个物理页 struct mutex lock; #ifdef CONFIG_CMA_DEBUGFS struct hlist_head mem_head; spinlock_t mem_head_lock; #endif const char *name; }; //mm/cma.c struct cma cma_areas[MAX_CMA_AREAS]; //17 CONFIG_CMA_AREAS+1 unsigned cma_area_count;
内核允许系统上有多个CMA区域,因此定义了一个数组 cma_areas[] 来保存所有的CMA区域,最大支持的个数可配置。
假设 order_per_bit=1 的,每个bit代表2个物理页,为0则每个bit代表1个物理页。
CMA初始化的时候,也会将CMA内存以pageblock 4MB的大小,插入到伙伴系统的 MIGRATE_CMA 类型的空闲链表中。只有用户向伙伴系统申请的内存是可移动的,才可能会去CMA链表上去拿内存。
伙伴系统在初始化的时候将内存分为4MB大小的pageblock,每个pageblock内存块都有物理页的类型,MIGRATE_UNMOVABLE、MIGRATE_MOVABLE 等。
假设DMA模块现在要去申请两个pageblock大小的连续物理内存,系统会找到CMA内存在伙伴系统中的位置,将其对应的pageblock设置为 MIGRATE_ISOLATE 类型(此时其上所有物理页都变为这个类型),表示此pageblock已经被当做CMA内存拿去使用了,伙伴系统不要分配它了。
4. CMA初始化
初始化有两种方式,一个是通过内核配置,另一个是通过设备树dts文件。
设备树中 reserved-memory 节点也是受伙伴系统管理的,但是不会通过伙伴系统的接口给用户使用了。保留下来这块内存用于专门的用途。compatible = "shared-dma-pool" 指定的可以用作CMA区域,内核根据这个字眼去解析然后初始化成一个struct cma结构。
/ { reserved-memory { #address-cells = <0x02>; #size-cells = <0x02>; ranges; phandle = <0x2ea>; linux,cma { compatible = "shared-dma-pool"; alloc-ranges = <0x00 0x00 0x00 0xffffffff>; reusable; alignment = <0x00 0x400000>; size = <0x00 0x2000000>; //32M linux,cma-default; phandle = <0x2eb>; }; qseecom_region { compatible = "shared-dma-pool"; alloc-ranges = <0x00 0x00 0x00 0xffffffff>; no-map; alignment = <0x00 0x400000>; size = <0x00 0x1400000>; //20M phandle = <0x02>; }; qseecom_ta_region { compatible = "shared-dma-pool"; alloc-ranges = <0x00 0x00 0x00 0xffffffff>; no-map; alignment = <0x00 0x400000>; size = <0x00 0x1000000>; //16M phandle = <0x03>; }; mem_dump_region { compatible = "shared-dma-pool"; alloc-ranges = <0x00 0x00 0x00 0xffffffff>; reusable; size = <0x00 0x1000000>; //16M phandle = <0x05>; }; cnss_wlan_region { compatible = "shared-dma-pool"; alloc-ranges = <0x00 0x00 0x00 0xffffffff>; reusable; alignment = <0x00 0x400000>; size = <0x00 0x6000000>; //96M phandle = <0x18b>; }; pmem_shared_region { reg = <0x01 0x66500000 0x00 0x51400000>; label = "pmem_shared_mem"; phandle = <0x2ec>; }; ramoops@800000000 { compatible = "ramoops"; reg = <0x08 0x00 0x00 0x200000>; record-size = <0x40000>; console-size = <0x40000>; pmsg-size = <0x40000>; }; }; };
内核启动log打印:
# cat kernel.txt | grep OF: <6>[ 0.000000] (0)[0:swapper]OF: reserved mem: initialized node qseecom_region, compatible id shared-dma-pool <6>[ 0.000000] (0)[0:swapper]OF: reserved mem: initialized node qseecom_ta_region, compatible id shared-dma-pool <6>[ 0.000000] (0)[0:swapper]OF: reserved mem: initialized node mem_dump_region, compatible id shared-dma-pool <6>[ 0.000000] (0)[0:swapper]OF: reserved mem: initialized node cnss_wlan_region, compatible id shared-dma-pool <6>[ 0.000000] (0)[0:swapper]OF: reserved mem: initialized node linux,cma, compatible id shared-dma-pool <6>[ 0.000000] (0)[0:swapper]Memory: 13692116K/14227228K available (18344K kernel code, 3350K rwdata, 12772K rodata, 4224K init, 2509K bss, 387656K reserved, 147456K cma-reserved)
注:147456K=144MB,和 cat /proc/pagetypeinfo 对应的上。设备树前面加起来是180MB,对应不上 #####。
5. CMA相关接口
/sys # find ./ -name "*cma*" ./kernel/debug/tracing/events/cma ./kernel/debug/tracing/events/cma/cma_alloc_busy_retry ./kernel/debug/tracing/events/cma/cma_alloc ./kernel/debug/tracing/events/cma/cma_alloc_start ./kernel/debug/tracing/events/cma/cma_release /sys/firmware/devicetree/base/reserved-memory # ls -l drwxr-xr-x 2 root root 0 2024-07-02 20:26 cnss_wlan_region drwxr-xr-x 2 root root 0 2024-07-02 20:26 linux,cma drwxr-xr-x 2 root root 0 2024-07-02 20:26 mem_dump_region drwxr-xr-x 2 root root 0 2024-07-02 20:26 pmem_shared_region drwxr-xr-x 2 root root 0 2024-07-02 20:26 qseecom_region drwxr-xr-x 2 root root 0 2024-07-02 20:26 qseecom_ta_region drwxr-xr-x 2 root root 0 2024-07-02 20:26 ramoops@800000000
标签:13,region,cma,CMA,内存,shared,root From: https://www.cnblogs.com/hellokitty2/p/18280545