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;
- }
- }
- }
- }
可见,过程是比较简单而清晰的。