设为首页 加入收藏

TOP

Linux内核最新的连续内存分配器(CMA)——避免预留大块内存【转】(一)
2019-09-01 23:09:14 】 浏览:153
Tags:Linux 内核 最新 连续 内存 分配器 CMA 避免 预留 大块

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

1. 声明连续内存

内核启动过程中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.
   &nbs
首页 上一页 1 2 3 4 5 6 下一页 尾页 1/6/6
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇微处理器功耗来源 下一篇a simple game based on RT-Thread

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目