Linux内核最新的连续内存分配器 CMA ——避免预留大块内存

               

                                                                                                                                              by 宋宝华

在我们使用ARM等嵌入式Linux系统的时候,一个头疼的问题是GPU,Camera,HDMI等都需要预留大量连续内存,这部分内存平时不用,但是一般的做法又必须先预留着。目前,Marek Szyprowski和Michal Nazarewicz实现了一套全新的Contiguous Memory Allocator。通过这套机制,我们可以做到不预留内存,这些内存平时是可用的,只有当需要的时候才被分配给Camera,HDMI等设备。下面分析它的基本代码流程。

声明连续内存

内核启动过程中arch/arm/mm/init.c中的arm_memblock_init()会调用dma_contiguous_reserve(min(arm_dma_limit, arm_lowmem_limit));

该函数位于:drivers/base/dma-contiguous.c

/** * dma_contiguous_reserve() - reserve area for contiguous memory handling * @limit: End address of the reserved memory (optional, 0 for any). * * This function reserves memory from early allocator. It should be * called by arch specific code once the early allocator (memblock or bootmem) * has been activated and all other subsystems have already allocated/reserved * memory. */void __init dma_contiguous_reserve(phys_addr_t limit){        unsigned long selected_size = 0;        pr_debug("%s(limit %08lx)\n", __func__, (unsigned long)limit);        if (size_cmdline != -1) {                selected_size = size_cmdline;        } else {#ifdef CONFIG_CMA_SIZE_SEL_MBYTES                selected_size = size_bytes;#elif defined(CONFIG_CMA_SIZE_SEL_PERCENTAGE)                selected_size = cma_early_percent_memory();#elif defined(CONFIG_CMA_SIZE_SEL_MIN)                selected_size = min(size_bytes, cma_early_percent_memory());#elif defined(CONFIG_CMA_SIZE_SEL_MAX)                selected_size = max(size_bytes, cma_early_percent_memory());#endif        }           if (selected_size) {                pr_debug("%s: reserving %ld MiB for global area\n", __func__,                         selected_size / SZ_1M);                dma_declare_contiguous(NULL, selected_size, 0, limit);        }   };

其中的size_bytes定义为:

static const unsigned long size_bytes = CMA_SIZE_MBYTES * SZ_1M; 默认情况下,CMA_SIZE_MBYTES会被定义为16MB,来源于CONFIG_CMA_SIZE_MBYTES=16

->

int __init dma_declare_contiguous(struct device *dev, unsigned long size,                                  phys_addr_t base, phys_addr_t limit){        ...        /* Reserve memory */        if (base) {                if (memblock_is_region_reserved(base, size) ||                    memblock_reserve(base, size) < 0) {                        base = -EBUSY;                        goto err;                }        } else {                /*                 * Use __memblock_alloc_base() since                 * memblock_alloc_base() panic()s.                 */                phys_addr_t addr = __memblock_alloc_base(size, alignment, limit);                if (!addr) {                        base = -ENOMEM;                        goto err;                } else if (addr + size > ~(unsigned long)0) {                        memblock_free(addr, size);                        base = -EINVAL;                        base = -EINVAL;                        goto err;                } else {                        base = addr;                }        }        /*         * Each reserved area must be initialised later, when more kernel         * subsystems (like slab allocator) are available.         */        r->start = base;        r->size = size;        r->dev = dev;        cma_reserved_count++;        pr_info("CMA: reserved %ld MiB at %08lx\n", size / SZ_1M,                (unsigned long)base);        /* Architecture specific contiguous memory fixup. */        dma_contiguous_early_fixup(base, size);        return 0;err:        pr_err("CMA: failed to reserve %ld MiB\n", size / SZ_1M);        return base;} 

由此可见,连续内存区域也是在内核启动的早期,通过__memblock_alloc_base()拿到的。

另外:

drivers/base/dma-contiguous.c里面的core_initcall()会导致cma_init_reserved_areas()被调用:

static int __init cma_init_reserved_areas(void){        struct cma_reserved *r = cma_reserved;        unsigned i = cma_reserved_count;        pr_debug("%s()\n", __func__);        for (; i; --i, ++r) {                struct cma *cma;                cma = cma_create_area(PFN_DOWN(r->start),                                      r->size >> PAGE_SHIFT);                if (!IS_ERR(cma))                        dev_set_cma_area(r->dev, cma);        }        return 0;}core_initcall(cma_init_reserved_areas);

cma_create_area()会调用cma_activate_area(),cma_activa
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值