保留内存(PMEM/ION)申请

来源:互联网 发布:sql@id 编辑:程序博客网 时间:2024/04/29 09:36

chipset: msm8x25

codebase: android4.1


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

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

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

万事从start_kernel开始:

[html] view plaincopy
  1. asmlinkage void __init start_kernel(void)  
  2. {  
  3.     char * command_line;  
  4.     extern const struct kernel_param __start___param[], __stop___param[];  
  5. //snip  
  6.     setup_arch(&command_line);  
  7. //snip  
  8.   
  9. }  
  10.   
  11. void __init setup_arch(char **cmdline_p)  
  12. {  
  13.     struct machine_desc *mdesc;  
  14.   
  15.     setup_processor();  
  16.     mdesc = setup_machine_fdt(__atags_pointer);  
  17.     if (!mdesc)  
  18.         mdesc = setup_machine_tags(machine_arch_type);  
  19.     machine_desc = mdesc;  
  20.     machine_name = mdesc->name;  
  21.   
  22. //snip  
  23.     arm_memblock_init(&meminfo, mdesc);  
  24.   
  25.     paging_init(mdesc);  
  26. //snip  
  27.   
  28.     if (mdesc->init_early)  
  29.         mdesc->init_early();  
  30. }  
  31.   
  32. void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)  
  33. {  
  34. //snip  
  35.   
  36.     /* reserve any platform specific memblock areas */  
  37.     /*调用平台相关函数指针,这里为board-msm7x27.c中的  
  38. msm7x27a_reserve_info 的msm7x27a_calculate_reserve_size函数。  
  39. */  
  40.     if (mdesc->reserve)  
  41.         mdesc->reserve();  
  42. //snip  
  43. }  

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

我们对应的地方去:

[html] view plaincopy
  1. MACHINE_START(MSM7X27A_SURF, "QCT MSM7x27a SURF")  
  2.     .atag_offset    = 0x100,  
  3.     .map_io     = msm_common_io_init,  
  4.     .reserve    = msm7x27a_reserve,  
  5.     .init_irq   = msm_init_irq,  
  6.     .init_machine   = msm7x2x_init,  
  7.     .timer      = &msm_timer,  
  8.     .init_early     = msm7x2x_init_early,  
  9.     .handle_irq = vic_handle_irq,  
  10. MACHINE_END  
  11.   
  12. static void __init msm7x27a_reserve(void)  
  13. {  
  14.     reserve_info = &msm7x27a_reserve_info;  
  15.     msm_reserve();  
  16. }  
  17.   
  18. void __init msm_reserve(void)  
  19. {  
  20.     unsigned long msm_fixed_area_size;  
  21.     unsigned long msm_fixed_area_start;  
  22.   
  23.     /*初始化内存池相关结构,看来它想讲申请的内存放进内存池使用呀!*/  
  24.     memory_pool_init();  
  25. /* reserve_info 即函数msm7x27a_reserve得到的reserve_info结构体,一会看这个函数如何计算size的? */  
  26.     reserve_info->calculate_reserve_sizes();  
  27.   
  28.     msm_fixed_area_size = reserve_info->fixed_area_size;  
  29.     msm_fixed_area_start = reserve_info->fixed_area_start;  
  30.     if (msm_fixed_area_size)  
  31.         if (msm_fixed_area_start > reserve_info->low_unstable_address  
  32.             - MAX_FIXED_AREA_SIZE)  
  33.             reserve_info->low_unstable_address =  
  34.             msm_fixed_area_start;  
  35.     /*查找物理上是否有连续的内存比mt->limit大,然后取两者的较大者保存。*/  
  36.     calculate_reserve_limits();  
  37.     /*查看需要保留的size是否比mt->limit大,取两者的较小者保存。*/  
  38.     adjust_reserve_sizes();  
  39.     /*物理上真正分配一段保留内存给申请者,相对应address也保存到memtype_reserve_table结构中。*/  
  40.     reserve_memory_for_mempools();  
  41.     /*初始化内存池*/  
  42.     initialize_mempools();  
  43. }  

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

reserve_info是值是msm7x27a_reserve_info,对应如下:

[html] view plaincopy
  1. static struct reserve_info msm7x27a_reserve_info __initdata = {  
  2.     .memtype_reserve_table = msm7x27a_reserve_table,  
  3.     .calculate_reserve_sizes = msm7x27a_calculate_reserve_sizes,  
  4.     .paddr_to_memtype = msm7x27a_paddr_to_memtype,  
  5. };  

第一步: 计算size:

msm7x27a_calculate_reserve_sizes():

[html] view plaincopy
  1. static void __init msm7x27a_calculate_reserve_sizes(void)  
  2. {  
  3.     fix_sizes();  
  4.     size_pmem_devices();  
  5.     reserve_pmem_memory();  
  6.     size_ion_devices();  
  7.     reserve_ion_memory();  
  8. }  
  9.   
  10. static void fix_sizes(void)  
  11. {  
  12.     if (machine_is_msm7625a_surf() || machine_is_msm7625a_ffa()) {  
  13.         pmem_mdp_size = MSM7x25A_MSM_PMEM_MDP_SIZE;  
  14.         pmem_adsp_size = MSM7x25A_MSM_PMEM_ADSP_SIZE;  
  15.     } else {  
  16.         /*初始化的时候不是有赋值过了吗?  
  17.         重新赋值一遍干嘛?*/  
  18.         pmem_mdp_size = MSM_PMEM_MDP_SIZE;  
  19.         pmem_adsp_size = MSM_PMEM_ADSP_SIZE;  
  20.     }  
  21.     /*camera 在使用ZSL机制时需要大内存*/  
  22.     if (get_ddr_size() > SZ_512M)  
  23.         pmem_adsp_size = CAMERA_ZSL_SIZE;  
  24.   
  25.     /*ION比PMEM的audio size多了个EBI1 size,其实PMEM在调用  
  26. reserve_pmem_memory()时也增加了这部分内存.*/  
  27. #ifdef CONFIG_ION_MSM  
  28.     msm_ion_camera_size = pmem_adsp_size;  
  29.     msm_ion_audio_size = (MSM_PMEM_AUDIO_SIZE + PMEM_KERNEL_EBI1_SIZE);  
  30.     msm_ion_sf_size = pmem_mdp_size;  
  31. #endif  
  32. }  
  33.   
  34.   
  35. static void __init size_pmem_devices(void)  
  36. {  
  37. /*只有PMEM定义了,但是ION没有定义的情况下才运行这段代码*/  
  38. #ifdef CONFIG_ANDROID_PMEM  
  39. #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION  
  40.     unsigned int i;  
  41.     unsigned int reusable_count = 0;  
  42.   
  43.     android_pmem_adsp_pdata.size = pmem_adsp_size;  
  44.     android_pmem_pdata.size = pmem_mdp_size;  
  45.     android_pmem_audio_pdata.size = pmem_audio_size;  
  46.   
  47.     fmem_pdata.size = 0;  
  48.     fmem_pdata.align = PAGE_SIZE;  
  49.   
  50.     /* Find pmem devices that should use FMEM (reusable) memory.  
  51.      */  
  52.      /*寻找是否有可以reusable的PMEM并且标记,这里  
  53.     adsp这块PMEM会被reuse.*/  
  54.     for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i) {  
  55.         struct android_pmem_platform_data *pdata = pmem_pdata_array[i];  
  56.   
  57.         if (!reusable_count && pdata->reusable)  
  58.             fmem_pdata.size += pdata->size;  
  59.   
  60.         reusable_count += (pdata->reusable) ? 1 : 0;  
  61.   
  62.         if (pdata->reusable && reusable_count > 1) {  
  63.             pr_err("%s: Too many PMEM devices specified as reusable.   
[html] view plaincopy
  1. PMEM device %s was not configured as reusable.\n",  
  2.                 __func__, pdata->name);  
  3.             pdata->reusable = 0;  
  4.         }  
  5.     }  
  6. #endif  
  7. #endif  
  8. }  
  9.   
  10. static void __init reserve_pmem_memory(void)  
  11. {  
  12. #ifdef CONFIG_ANDROID_PMEM  
  13. #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION  
  14.     unsigned int i;  
  15.     /*将前面得到的adsp/audio/mdp size计算到msm7x27a_reserve_table  
  16.     中。*/  
  17.     for (i = 0; i < ARRAY_SIZE(pmem_pdata_array); ++i)  
  18.         reserve_memory_for(pmem_pdata_array[i]);  
  19.     /*也将ebi1 size 计算入内。*/  
  20.     msm7x27a_reserve_table[MEMTYPE_EBI1].size += pmem_kernel_ebi1_size;  
  21. #endif  
  22. #endif  
  23. }  
  24.   
  25. #ifdef CONFIG_ANDROID_PMEM  
  26. #ifndef CONFIG_MSM_MULTIMEDIA_USE_ION  
  27. static void __init reserve_memory_for(struct android_pmem_platform_data *p)  
  28. {  
  29.     msm7x27a_reserve_table[p->memory_type].size += p->size;  
  30. }  
  31. #endif  
  32. #endif  
  33.   
  34. static void __init size_ion_devices(void)  
  35. {  
  36. /*使用ION时也保存相同的size。*/  
  37. #ifdef CONFIG_MSM_MULTIMEDIA_USE_ION  
  38.     ion_pdata.heaps[1].size = msm_ion_camera_size;  
  39.     ion_pdata.heaps[2].size = msm_ion_audio_size;  
  40.     ion_pdata.heaps[3].size = msm_ion_sf_size;  
  41. #endif  
  42. }  
  43.   
  44. static void __init reserve_ion_memory(void)  
  45. {  
  46. /*又保存size到msm7x27a_reserve_table中,所以PMEM和ION没必要同时  
  47. 使用。*/  
  48. #if defined(CONFIG_ION_MSM) && defined(CONFIG_MSM_MULTIMEDIA_USE_ION)  
  49.     msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_camera_size;  
  50.     msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_audio_size;  
  51.     msm7x27a_reserve_table[MEMTYPE_EBI1].size += msm_ion_sf_size;  
  52. #endif  
  53. }  

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

[html] view plaincopy
  1. static void __init calculate_reserve_limits(void)  
  2. {  
  3.     int i;  
  4.     struct membank *mb;  
  5.     int memtype;  
  6.     struct memtype_reserve *mt;  
  7.     unsigned long size;  
  8.   
  9.     for (i = 0mb = &meminfo.bank[0]; i < meminfo.nr_banks; i++, mb++)  {  
  10.   
  11. printk("Kris start:0x%x size:0x%lx, highmem:0x%d\n", mb->start, mb->size, mb->highmem);  
  12.     }  
  13.     /*meminfo为系统保存的物理内存信息,  
  14.     这里的for循环主要计算物理上最大的  
  15.     连续的bank也就是说连续的物理内存大小是  
  16.     多少,然后和mt->limit比较,取较大者。*/  
  17.     for (i = 0mb = &meminfo.bank[0]; i < meminfo.nr_banks; i++, mb++)  {  
  18.         memtype = reserve_info->paddr_to_memtype(mb->start);  
  19.         if (memtype == MEMTYPE_NONE) {  
  20.             pr_warning("unknown memory type for bank at %lx\n",  
  21.                 (long unsigned int)mb->start);  
  22.             continue;  
  23.         }  
  24.         mt = &reserve_info->memtype_reserve_table[memtype];  
  25.         size = total_stable_size(i);  
  26.         mt->limit = max(mt->limit, size);  
  27.     }  
  28. }  

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

[html] view plaincopy
  1. static void __init adjust_reserve_sizes(void)  
  2. {  
  3.     int i;  
  4.     struct memtype_reserve *mt;  
  5.   
  6.     mt = &reserve_info->memtype_reserve_table[0];  
  7.   
  8.     for (i = 0; i < MEMTYPE_MAX; i++, mt++) {  
  9.         if (mt->flags & MEMTYPE_FLAGS_1M_ALIGN)  
  10.             mt->size = (mt->size + SECTION_SIZE - 1) & SECTION_MASK;  
  11.         printk("type:%d mt->size:0x%lx mt->limit:0x%lx\n", i, mt->size, mt->limit);  
  12.         if (mt->size > mt->limit) {  
  13.             pr_warning("%lx size for %s too large, setting to %lx\n",  
  14.                 mt->size, memtype_name[i], mt->limit);  
  15.             mt->size = mt->limit;  
  16.         }  
  17.     }  
  18. }  

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

[html] view plaincopy
  1. static void __init reserve_memory_for_mempools(void)  
  2. {  
  3.     int i, memtype, membank_type;  
  4.     struct memtype_reserve *mt;  
  5.     struct membank *mb;  
  6.     int ret;  
  7.     unsigned long size;  
  8.   
  9.     mt = &reserve_info->memtype_reserve_table[0];  
  10.     for (memtype = 0; memtype < MEMTYPE_MAX; memtype++, mt++) {  
  11.         if (mt->flags & MEMTYPE_FLAGS_FIXED || !mt->size)  
  12.             continue;  
  13.   
  14.         /* We know we will find memory bank(s) of the proper size  
  15.          * as we have limited the size of the memory pool for  
  16.          * each memory type to the largest total size of the memory  
  17.          * banks which are contiguous and of the correct memory type.  
  18.          * Choose the memory bank with the highest physical  
  19.          * address which is large enough, so that we will not  
  20.          * take memory from the lowest memory bank which the kernel  
  21.          * is in (and cause boot problems) and so that we might  
  22.          * be able to steal memory that would otherwise become  
  23.          * highmem. However, do not use unstable memory.  
  24.          */  
  25.         for (i = meminfo.nr_banks - 1; i >= 0; i--) {  
  26.             mb = &meminfo.bank[i];  
  27.             membank_type =  
  28.                 reserve_info->paddr_to_memtype(mb->start);  
  29.             if (memtype != membank_type)  
  30.                 continue;  
  31.             size = total_stable_size(i);  
  32.             if (size >= mt->size) {  
  33.                 size = stable_size(mb,  
  34.                     reserve_info->low_unstable_address);  
  35.                 if (!size)  
  36.                     continue;  
  37.                 /* mt->size may be larger than size, all this  
  38.                  * means is that we are carving the memory pool  
  39.                  * out of multiple contiguous memory banks.  
  40.                  */  
  41.                 /*得到保留内存的起始地址。*/  
  42.                 mt->start = mb->start + (size - mt->size);  
  43.                 printk("kris mt->size:0x%lx mt->start:0x%lx mb->start:0x%x\n",   
  44.                     mt->size, mt->start, mb->start);  
  45.                 /*将保留内存区域从系统可用动态内存部分  
  46.                 移除。*/  
  47.                 ret = memblock_remove(mt->start, mt->size);  
  48.                 BUG_ON(ret);  
  49.                 break;  
  50.             }  
  51.         }  
  52.     }  
  53. }  

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

0 0