在以前的驱动中,一般给LCD/GPU/camera预留部分内存,满足这些模块内存分配的同时,也能够提供物理地址连续内存.
但是,如果GPU/camera/LCD没有使用时,这部分内存就白白浪费了,所以就有了CMA机制.
CMA给驱动提供了一种分配连续内存的方法, 在驱动没有分配CMA内存时,这部分内存可以用于migrate type为moveable的内存分配,在驱动需要CMA内存时,先释放之前分配的CMA内存,然后重新给moveable内存进行映射.
DMA内存分配可以基于CMA提供的接口分配内存.
1. CMA内存的初始化:
setup_arch--->arm64_memblock_init->dma_contiguous_reserve->dma_contiguous_reserve_area->cma_declare_contiguous->cma_init_reserved_mem
定义一个全局的CMA内存,每个驱动程序也可以定制自己的CMA内存.
可以通过: cma_init_reserved_mem函数申请保留一段内存用于CMA操作。
当CMA 区域注册完成后,core_initcall(cma_init_reserved_areas); 把CMA内存释放到伙伴系统中.
2. CMA内存分配和释放
struct page *cma_alloc(struct cma *cma, size_t count, unsigned int align)
bool cma_release(struct cma *cma, const struct page *pages, unsigned int count)
3驱动定义自己的CMA内存
1. 在dts的reserved-memory结点中定义预留内存的起始地址和size.
size必须是(page_size)<<MAX(MAX_ORDER-,pageblock_order)的整数倍,
起始地址也必须(page_size)<<MAX_ORDER-1对齐,否则调用cma_init_reserved_mem添加时会报错
reserved-memory{
cma_test {
compatible = "cma_test";
reg = <0x0 0xC0800000 0x800000>;
};
}
2. 在驱动中定义reserved-memory处理函数
static int __init reserved_cma_test(struct reserved_mem *rmem)
{
cma_base = rmem->base ;
cma_size = rmem->size ;
/*添加cma内存,cma_init_reserved_mem的调用必须在cma_init_reserved_areas之前 */
ret = cma_init_reserved_mem(cma_base,cma_size,0,&cma_test);
if(ret){
printk(KERN_ERR"add cma_test error %d\n",ret);
}
return 0;
}
RESERVEDMEM_OF_DECLARE(cma_test, "cma_test", reserved_cma_test);
3.分配cma内存
注意,这两个分配函数可能会休眠,不能在原子上下文调用.
cma_alloc(cma_test,8,0);
cma_release(cma_test,8,pages);
4.如果需要把cma内存预留为DMA操作,
首先需要把DMA分配函数和cma关联起来
arch_setup_dma_ops(dev, 0, 0, NULL, 1);//需要设置coherent=1
dev_set_cma_area(dev, cma_test);
然后进行分配DMA分配,最终会调用cma_alloc来从我们预留的内存中分配
dma_alloc_coherent(dev,size,GFP_KERNEL)//必须要允许休眠
http://www.wowotech.net/memory_management/cma.html