CMA内存分配

 在以前的驱动中,一般给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)<

起始地址也必须(page_size)<

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

 

你可能感兴趣的:(内存管理)