连续物理内存

Linux Kernel 中的 CMA 即连续内存区管理,其提供配置为 CONFIG_CMA 和 CONFIG_CMA_DEBUG,其管理的是一块块连续内存块,这个在物理地址上是连续的。

这点跟我们使用的伙伴算法以及虚拟地址有点不一样,尽管伙伴算法中使用 kmalloc 申请连续物理内存也可以,但是在长时间测试环境下,连续物理内存可能申请不到。

因此,内核设计者设计了 CMA,即连续物理内存管理,其定制了一块连续物理内存,专门用于需要连续物理内存的场景,比如 DMA。

在嵌入式设备中,很多外设都没有支持 scatter-getter 和 IO map,都需要连续内存块的操作。比如摄像机、硬件视频解码器等,这些设备往往需要较大的内存缓冲区(一个 200 万像素的高清摄像机,需要超过 6M 的内存),kmalloc 内存分配机制对于这么大的内存是没有效果的。一些嵌入式设备对缓冲区有一些额外的要求,比如在含有多个 bank 的设备中,要求只能在特定的 bank 中分配内存,还有一些要定内存边界对齐的缓冲区。

CMA 框架采用统一的连续内存分配机制,并为ie这些设备驱动提供简单的 API,而且是可以定制化和模块化的。

CMA 机制

CMA 全称叫做 continuous memory allocator,它是为了便于进行连续物理内存申请的一块区域,一般我们把这块区域定义为 reserved-memory。

img

早期的 Linux 内核中没有 CMA 的实现,如果驱动想要申请一大块的物理连续内存,那么只能通过预留专属内存的形式,然后在驱动中使用 ioremap 来映射后作为私有内存使用。这样带来的后果就是有一部分内存将被预留出来不能作为系统中的通用内存来使用,比如 camera、audio 设备,它们在工作时是需要大块连续内存进行 DMA 操作的,而当这些设备不工作时,预留的内存也无法被其它模块使用。

引入 CMA 就是为了解决这个问题的,定义为 CMA 区域的内存,也是由操作系统来管理的,当一个驱动模块想要申请大块连续内存时,通过内存管理子系统把 CMA 区域的内存进行迁移,空出连续内存给驱动使用;而当驱动模块释放这块连续内存后,它又被归还给操作系统管理,可以给其它申请者分配使用。

CMA 数据结构

继续参考内核之旅

CMA 内存分配和释放

当一个内核模块要使用 CMA 内存时,使用的接口依然是 DMA 的接口

extern void *
dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *dma_handle,
           gfp_t flag);

extern void
dma_free_coherent(struct device *dev, size_t size, void *cpu_addr,
            dma_addr_t dma_handle);

继续参考内核之旅

参考

CMA机制 ,Linux 内核之旅,CMA 与 DMA 的关系

内存之旅——如何提升CMA利用率? 为什么需要 CMA?回答的很好