保留内存(PMEM/ION)申请

chipset: msm8x25

codebase: android4.1


PMEM是高通使用的固定内存分配机制,ION是Google为了使各家厂商使用同一种固定内存分配机制而出现的产物。

当然在ION使用的情况下,PMEM也是可以被定义使用的,主要看用户空间选择哪个了,不过两者并存实在没这个必要,毕竟很浪费内存。

先看下kernel在开机的时候是如何申请这部分内存作为PMEM使用的。

万事从start_kernel开始:

asmlinkage void __init start_kernel(void)
{
	char * command_line;
	extern const struct kernel_param __start___param[], __stop___param[];
//snip
	setup_arch(&command_line);
//snip

}

void __init setup_arch(char **cmdline_p)
{
	struct machine_desc *mdesc;

	setup_processor();
	mdesc = setup_machine_fdt(__atags_pointer);
	if (!mdesc)
		mdesc = setup_machine_tags(machine_arch_type);
	machine_desc = mdesc;
	machine_name = mdesc->name;

//snip
	arm_memblock_init(&meminfo, mdesc);

	paging_init(mdesc);
//snip

	if (mdesc->init_early)
		mdesc->init_early();
}

void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
{
//snip

	/* reserve any platform specific memblock areas */
	/*调用平台相关函数指针,这里为board-msm7x27.c中的
msm7x27a_reserve_info 的msm7x27a_calculate_reserve_size函数。
*/
	if (mdesc->reserve)
		mdesc->reserve();
//snip
}

mdesc结构为struct machine_desc,不了解的可以学习下这个结构体的用法,网上一搜一大把,这里直接转到

我们对应的地方去:

MACHINE_START(MSM7X27A_SURF, "QCT MSM7x27a SURF")
	.atag_offset	= 0x100,
	.map_io		= msm_common_io_init,
	.reserve	= msm7x27a_reserve,
	.init_irq	= msm_init_irq,
	.init_machine	= msm7x2x_init,
	.timer		= &msm_timer,
	.init_early     = msm7x2x_init_early,
	.handle_irq	= vic_handle_irq,
MACHINE_END

static void __init msm7x27a_reserve(void)
{
	reserve_info = &msm7x27a_reserve_info;
	msm_reserve();
}

void __init msm_reserve(void)
{
	unsigned long msm_fixed_area_size;
	unsigned long msm_fixed_area_start;

	/*初始化内存池相关结构,看来它想讲申请的内存放进内存池使用呀!*/
	memory_pool_init();
/* reserve_info 即函数msm7x27a_reserve得到的reserve_info结构体,一会看这个函数如何计算size的? */
	reserve_info->calculate_reserve_sizes();

	msm_fixed_area_size = reserve_info->fixed_area_size;
	msm_fixed_area_start = reserve_info->fixed_area_start;
	if (msm_fixed_area_size)
		if (msm_fixed_area_start > reserve_info->low_unstable_address
			- MAX_FIXED_AREA_SIZE)
			reserve_info->low_unstable_address =
			msm_fixed_area_start;
	/*查找物理上是否有连续的内存比mt->limit大,然后取两者的较大者保存。*/
	calculate_reserve_limits();
	/*查看需要保留的size是否比mt->limit大,取两者的较小者保存。*/
	adjust_reserve_sizes();
	/*物理上真正分配一段保留内存给申请者,相对应address也保存到memtype_reserve_table结构中。*/
	reserve_memory_for_mempools();
	/*初始化内存池*/
	initialize_mempools();
}

上面重要几步都做了解释,流程也比较清晰:

reserve_info是值是msm7x27a_reserve_info,对应如下:

static struct reserve_info msm7x27a_reserve_info __initdata = {
	.memtype_reserve_table = msm7x27a_reserve_table,
	.calculate_reserve_sizes = msm7x27a_calculate_reserve_sizes,
	.paddr_to_memtype = msm7x27a_paddr_to_memtype,
};

第一步: 计算size:

msm7x27a_calculate_reserve_sizes():

static void __init msm7x27a_calculate_reserve_sizes(void)
{
	fix_sizes();
	size_pmem_devices();
	reserve_pmem_memory();
	size_ion_devices();
	reserve_ion_memory();
}

static void fix_sizes(void)
{
	if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {
		pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE;
		pmem_adsp_size = MSM7x25A_MSM_PMEM_ADSP_SIZE;
	} else {
		/*初始化的时候不是有赋值过了吗?
		重新赋值一遍干嘛?*/
		pmem_mdp_size = MSM_PMEM_MDP_SIZE;
		pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
	}
	/*camera 在使用ZSL机制时需要大内存*/
	if (get_ddr_size() > SZ_512M)
		pmem_adsp_size = CAMERA_ZSL_SIZE;

	/*ION比PMEM的audio size多了个EBI1 size,其实PMEM在调用
reserve_pmem_memory()时也增加了这部分内存.*/
#ifdef CONFIG_ION_MSM
	msm_ion_camera_size = pmem_adsp_size;
	msm_ion_audio_size = (MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE);
	msm_ion_sf_size = pmem_mdp_size;
#endif
}


static void __init size_pmem_devices(void)
{
/*只有PMEM定义了,但是ION没有定义的情况下才运行这段代码*/
#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
	unsigned int i;
	unsigned int reusable_count = 0;

	android_pmem_adsp_pdata.size = pmem_adsp_size;
	android_pmem_pdata.size = pmem_mdp_size;
	android_pmem_audio_pdata.size = pmem_audio_size;

	fmem_pdata.size = 0;
	fmem_pdata.align = PAGE_SIZE;

	/* Find pmem devices that should use FMEM (reusable) memory.
	 */
	 /*寻找是否有可以reusable的PMEM并且标记,这里
	adsp这块PMEM会被reuse.*/
	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {
		struct android_pmem_platform_data *pdata = pmem_pdata_array[i];

		if (!reusable_count && pdata->reusable)
			fmem_pdata.size += pdata->size;

		reusable_count += (pdata->reusable) ? 1 : 0;

		if (pdata->reusable && reusable_count > 1) {
			pr_err("%s: Too many PMEM devices specified as reusable. 
PMEM device %s was not configured as reusable.\n",
				__func__, pdata->name);
			pdata->reusable = 0;
		}
	}
#endif
#endif
}

static void __init reserve_pmem_memory(void)
{
#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
	unsigned int i;
	/*将前面得到的adsp/audio/mdp size计算到msm7x27a_reserve_table
	中。*/
	for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)
		reserve_memory_for(pmem_pdata_array[i]);
	/*也将ebi1 size 计算入内。*/
	msm7x27a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;
#endif
#endif
}

#ifdef CONFIG_ANDROID_PMEM
#ifndef CONFIG_MSM_MULTIMEDIA_USE_ION
static void __init reserve_memory_for(struct android_pmem_platform_data *p)
{
	msm7x27a_reserve_table[p->memory_type].size += p->size;
}
#endif
#endif

static void __init size_ion_devices(void)
{
/*使用ION时也保存相同的size。*/
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
	ion_pdata.heaps[1].size = msm_ion_camera_size;
	ion_pdata.heaps[2].size = msm_ion_audio_size;
	ion_pdata.heaps[3].size = msm_ion_sf_size;
#endif
}

static void __init reserve_ion_memory(void)
{
/*又保存size到msm7x27a_reserve_table中,所以PMEM和ION没必要同时
使用。*/
#if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)
	msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_camera_size;
	msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_audio_size;
	msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;
#endif
}

第二步:计算物理连续内存最大为多少size,看size是否符合要求

static void __init calculate_reserve_limits(void)
{
	int i;
	struct membank *mb;
	int memtype;
	struct memtype_reserve *mt;
	unsigned long size;

	for (i = 0, mb = &meminfo.bank[0]; i < meminfo.nr_banks; i++, mb++)  {

printk("Kris start:0x%x size:0x%lx, highmem:0x%d\n", mb->start, mb->size, mb->highmem);
	}
	/*meminfo为系统保存的物理内存信息,
	这里的for循环主要计算物理上最大的
	连续的bank也就是说连续的物理内存大小是
	多少,然后和mt->limit比较,取较大者。*/
	for (i = 0, mb = &meminfo.bank[0]; i < meminfo.nr_banks; i++, mb++)  {
		memtype = reserve_info->paddr_to_memtype(mb->start);
		if (memtype == MEMTYPE_NONE) {
			pr_warning("unknown memory type for bank at %lx\n",
				(long unsigned int)mb->start);
			continue;
		}
		mt = &reserve_info->memtype_reserve_table[memtype];
		size = total_stable_size(i);
		mt->limit = max(mt->limit, size);
	}
}

第三步:查询PMEM/ION要申请的size是否查过了系统的物理连续内存限制,如果是,就将其缩小。

static void __init adjust_reserve_sizes(void)
{
	int i;
	struct memtype_reserve *mt;

	mt = &reserve_info->memtype_reserve_table[0];

	for (i = 0; i < MEMTYPE_MAX; i++, mt++) {
		if (mt->flags & MEMTYPE_FLAGS_1M_ALIGN)
			mt->size = (mt->size + SECTION_SIZE - 1) & SECTION_MASK;
		printk("type:%d mt->size:0x%lx mt->limit:0x%lx\n", i, mt->size, mt->limit);
		if (mt->size > mt->limit) {
			pr_warning("%lx size for %s too large, setting to %lx\n",
				mt->size, memtype_name[i], mt->limit);
			mt->size = mt->limit;
		}
	}
}

第四步:比较完之后,当然是要将这部分size作为保留区域留给PMEM/ION使用了。

static void __init reserve_memory_for_mempools(void)
{
	int i, memtype, membank_type;
	struct memtype_reserve *mt;
	struct membank *mb;
	int ret;
	unsigned long size;

	mt = &reserve_info->memtype_reserve_table[0];
	for (memtype = 0; memtype < MEMTYPE_MAX; memtype++, mt++) {
		if (mt->flags & MEMTYPE_FLAGS_FIXED || !mt->size)
			continue;

		/* We know we will find memory bank(s) of the proper size
		 * as we have limited the size of the memory pool for
		 * each memory type to the largest total size of the memory
		 * banks which are contiguous and of the correct memory type.
		 * Choose the memory bank with the highest physical
		 * address which is large enough, so that we will not
		 * take memory from the lowest memory bank which the kernel
		 * is in (and cause boot problems) and so that we might
		 * be able to steal memory that would otherwise become
		 * highmem. However, do not use unstable memory.
		 */
		for (i = meminfo.nr_banks - 1; i >= 0; i--) {
			mb = &meminfo.bank[i];
			membank_type =
				reserve_info->paddr_to_memtype(mb->start);
			if (memtype != membank_type)
				continue;
			size = total_stable_size(i);
			if (size >= mt->size) {
				size = stable_size(mb,
					reserve_info->low_unstable_address);
				if (!size)
					continue;
				/* mt->size may be larger than size, all this
				 * means is that we are carving the memory pool
				 * out of multiple contiguous memory banks.
				 */
				/*得到保留内存的起始地址。*/
				mt->start = mb->start + (size - mt->size);
				printk("kris mt->size:0x%lx mt->start:0x%lx mb->start:0x%x\n", 
					mt->size, mt->start, mb->start);
				/*将保留内存区域从系统可用动态内存部分
				移除。*/
				ret = memblock_remove(mt->start, mt->size);
				BUG_ON(ret);
				break;
			}
		}
	}
}

可见,过程是比较简单而清晰的。


20130116


你可能感兴趣的:(保留内存(PMEM/ION)申请)