平台: MSM8x25Q
系统: Android4.1
从上一篇ION基本概念中,我们了解了heaptype, heap id, client, handle以及如何使用,本篇再从原理上分析下ION的运作流程。
MSM8x25Q平台使用的是board-qrd7627.c,ION相关定义如下:
/**
* These heaps are listed in the order they will be allocated.
* Don't swap the order unless you know what you are doing!
*/
struct ion_platform_heap msm7627a_heaps[] = {
{
.id = ION_SYSTEM_HEAP_ID,
.type = ION_HEAP_TYPE_SYSTEM,
.name = ION_VMALLOC_HEAP_NAME,
},
#ifdef CONFIG_MSM_MULTIMEDIA_USE_ION
/* PMEM_ADSP = CAMERA */
{
.id = ION_CAMERA_HEAP_ID,
.type = CAMERA_HEAP_TYPE,
.name = ION_CAMERA_HEAP_NAME,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *)&co_mm_ion_pdata,
.priv = (void *)&ion_cma_device.dev,
},
/* AUDIO HEAP 1*/
{
.id = ION_AUDIO_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_AUDIO_HEAP_NAME,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *)&co_ion_pdata,
},
/* PMEM_MDP = SF */
{
.id = ION_SF_HEAP_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_SF_HEAP_NAME,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *)&co_ion_pdata,
},
/* AUDIO HEAP 2*/
{
.id = ION_AUDIO_HEAP_BL_ID,
.type = ION_HEAP_TYPE_CARVEOUT,
.name = ION_AUDIO_BL_HEAP_NAME,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *)&co_ion_pdata,
.base = BOOTLOADER_BASE_ADDR,
},
#endif
};
static struct ion_co_heap_pdata co_ion_pdata = {
.adjacent_mem_id = INVALID_HEAP_ID,
.align = PAGE_SIZE,
};
static struct ion_co_heap_pdata co_mm_ion_pdata = {
.adjacent_mem_id = INVALID_HEAP_ID,
.align = PAGE_SIZE,
};
static u64 msm_dmamask = DMA_BIT_MASK(32);
static struct platform_device ion_cma_device = {
.name = "ion-cma-device",
.id = -1,
.dev = {
.dma_mask = &msm_dmamask,
.coherent_dma_mask = DMA_BIT_MASK(32),
}
};
Qualcomm提示了不要轻易调换顺序,因为后面代码处理是将顺序定死了的,一旦你调换了,代码就无法正常运行了。
另外, 本系统中只使用了ION_HEAP_TYPE_CARVEOUT和 ION_HEAP_TYPE_SYSTEM这两种heap type.
对于ION_HEAP_TYPE_CARVEOUT的内存分配,后面将会发现,其实就是之前讲述过的使用mem pool来分配的。
Platform device如下,在msm_ion.c中用到。
static struct ion_platform_data ion_pdata = {
.nr = MSM_ION_HEAP_NUM,
.has_outer_cache = 1,
.heaps = msm7627a_heaps,
};
static struct platform_device ion_dev = {
.name = "ion-msm",
.id = 1,
.dev = { .platform_data = &ion_pdata },
};
ION初始化
转到msm_ion.c,ion.c的某些函数也被重新封装了下.万事都从设备匹配开始:
static struct platform_driver msm_ion_driver = {
.probe = msm_ion_probe,
.remove = msm_ion_remove,
.driver = { .name = "ion-msm" }
};
static int __init msm_ion_init(void)
{
/*调用msm_ion_probe */
return platform_driver_register(&msm_ion_driver);
}
static int msm_ion_probe(struct platform_device *pdev)
{
/*即board-qrd7627a.c中的ion_pdata */
struct ion_platform_data *pdata = pdev->dev.platform_data;
int err;
int i;
/*heap数量*/
num_heaps = pdata->nr;
/*分配struct ion_heap */
heaps = kcalloc(pdata->nr, sizeof(struct ion_heap *), GFP_KERNEL);
if (!heaps) {
err = -ENOMEM;
goto out;
}
/*创建节点,最终是/dev/ion,供用户空间操作。*/
idev = ion_device_create(NULL);
if (IS_ERR_OR_NULL(idev)) {
err = PTR_ERR(idev);
goto freeheaps;
}
/*最终是根据adjacent_mem_id 是否定义了来分配相邻内存,
我们没用到,忽略此函数。*/
msm_ion_heap_fixup(pdata->heaps, num_heaps);
/* create the heaps as specified in the board file */
for (i = 0; i < num_heaps; i++) {
struct ion_platform_heap *heap_data = &pdata->heaps[i];
/*分配ion*/
msm_ion_allocate(heap_data);
heap_data->has_outer_cache = pdata->has_outer_cache;
/*创建ion heap。*/
heaps[i] = ion_heap_create(heap_data);
if (IS_ERR_OR_NULL(heaps[i])) {
heaps[i] = 0;
continue;
} else {
if (heap_data->size)
pr_info("ION heap %s created at %lx "
"with size %x\n", heap_data->name,
heap_data->base,
heap_data->size);
else
pr_info("ION heap %s created\n",
heap_data->name);
}
/*创建的heap添加到idev中,以便后续使用。*/
ion_device_add_heap(idev, heaps[i]);
}
/*检查heap之间是否有重叠部分*/
check_for_heap_overlap(pdata->heaps, num_heaps);
platform_set_drvdata(pdev, idev);
return 0;
freeheaps:
kfree(heaps);
out:
return err;
}
通过ion_device_create创建/dev/ion节点:
struct ion_device *ion_device_create(long (*custom_ioctl)
(struct ion_client *client,
unsigned int cmd,
unsigned long arg))
{
struct ion_device *idev;
int ret;
idev = kzalloc(sizeof(struct ion_device), GFP_KERNEL);
if (!idev)
return ERR_PTR(-ENOMEM);
/*是个misc设备*/
idev->dev.minor = MISC_DYNAMIC_MINOR;
/*节点名字为ion*/
idev->dev.name = "ion";
/*fops为ion_fops,所以对应ion的操作都会调用ion_fops的函数指针。*/
idev->dev.fops = &ion_fops;
idev->dev.parent = NULL;
ret = misc_register(&idev->dev);
if (ret) {
pr_err("ion: failed to register misc device.\n");
return ERR_PTR(ret);
}
/*创建debugfs目录,路径为/sys/kernel/debug/ion/*/
idev->debug_root = debugfs_create_dir("ion", NULL);
if (IS_ERR_OR_NULL(idev->debug_root))
pr_err("ion: failed to create debug files.\n");
idev->custom_ioctl = custom_ioctl;
idev->buffers = RB_ROOT;
mutex_init(&idev->lock);
idev->heaps = RB_ROOT;
idev->clients = RB_ROOT;
/*在ion目录下创建一个check_leaked_fds文件,用来检查Ion的使用是否有内存泄漏。如果申请了ion之后不需要使用却没有释放,就会导致memory leak.*/
debugfs_create_file("check_leaked_fds", 0664, idev->debug_root, idev,
&debug_leak_fops);
return idev;
}
msm_ion_allocate&