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 }
我们对应的地方去:
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