kernel: 5.10
arch: arm64

1. 前言

CMA是一段连续的内存区域,它的所有页面都是可迁移类型,平时在不需要大块连续内存的时候,这段CMA区域可供系统或其它驱动使用,在驱动需要大块内存的时候,已占用的部分需要迁移出去,空闲出大块连续内存以供分配。

2. 配置CMA区域

有三种方式可以配置CMA区域大小,dts,commdline, 内核的配置项,优先级分别是dts > commandline > 内核配置项,分别举例如下:

  • In the device tree:
linux,cma {
  compatible = "shared-dma-pool";
  reusable;
  size = <0 0x3c000000>;
  alloc-ranges = <0 0x96000000 0 0x3c000000>;
  linux,cma-default;
};
  • On the kernel command line:
cma=256MB
  • In the kernel configuration:
CONFIG_CMA_SIZE_MBYTES=960
CONFIG_CMA_SIZE_PERCENTAGE=25
# CONFIG_CMA_SIZE_SEL_MBYTES is not set
# CONFIG_CMA_SIZE_SEL_PERCENTAGE is not set
CONFIG_CMA_SIZE_SEL_MIN=y
# CONFIG_CMA_SIZE_SEL_MAX is not set

3. CMA API

对于用户来讲,使用cma仍然会采用原有的dma接口来调用,这对用户是感知不到的,接口可参考DMA-API.txt

4. CMA的工作机制

  1. 首先必须在cmdline或dts或内核配置项中为cma预留区域;
  2. arm64_memblock_init中会解析预留区域,将这部分区域添加到memlbok.reserved,这其中包含了CMA定义的区域,这部分区域会被初始化给cma;
  3. bootmem_init->sparse_init会为所有的物理内存bank创建page;
  4. 初始化时cma_init_reserved_areas->cma_activate_area->init_cma_reserved_pageblock 将cma区域的空闲page给buddy,并标注这些pageblock的属性为MIGRATE_CMA;

mm_init->mem_init->memblock_free_all->free_low_memory_core_early 只是释放>memblock.memory的空闲空间给buddy,且排除所有的memblock.reserved区域

  1. 通过dma接口申请连续物理内存,就可能会从CMA中申请,如果发现CMA区域已经被其它用户申请则需要将这些页面进行迁移

参考文档

A deep dive into CMACMA模块学习笔记Contiguous Memory Allocator - CMA (Linux)DMA-API.txtDMA-API-HOWTO.txt