Chipset:MSM8x25Q
Codebase:Android 4.1
PMEM使用:
PMEM使用比较简单,分单进程使用和共享进程使用同一块PMEM。
单进程使用:
1. int master_fd = open(“/dev/pmem_xxx”,O_RDWR, 0);
2. 然后再mmap就可以使用了。
进程间共享PMEM:
进程A:
和单进程使用方法一样。
进程B:
1. int fd = open(“/dev/pmem_xxx”,O_RDWR, 0);
2. ioctl(fd, PMEM_CONNECT,master_fd) //PMEM_CONNECT表示准备要连接了,连接的PMEM对应的fd为master_fd,即进程A打开的PMEM对应的fd。
3. 然后作mmap就可以使用了。
因此关键是第二步,master_fd是从进程A传过来的,可以使用binder等通信机制。
PMEM对应的驱动代码流程也是比较简单的,利用了字符驱动的open/ioctl/mmap操作,下面直接分析代码。
PMEM初始化:
PMEM类似于ION里的carved-outmemory,先预留一块内存,然后需要使用的时候从上面分配一块。因此PMEM总有一天会被ION替代,至少我这么认为.
平台上定义了如下三个PMEM模块: pmem_adsp, pmem_audio, pmem(mdp_pmem)。
static struct android_pmem_platform_data android_pmem_adsp_pdata = {
.name = "pmem_adsp", //给adsp使用
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP, //都是使用bitmap算法,后面会讲到。
.cached = 1,
.memory_type = MEMTYPE_EBI1, //内存类型都是EBI1
};
static struct platform_device android_pmem_adsp_device = {
.name = "android_pmem",
.id = 1,
.dev = { .platform_data = &android_pmem_adsp_pdata },
};
static unsigned pmem_mdp_size = MSM_PMEM_MDP_SIZE;
static int __init pmem_mdp_size_setup(char *p)
{
pmem_mdp_size = memparse(p, NULL);
return 0;
}
/*可以通过传参来设置pmem mdp的size, 其他pmem模块也如此。*/
early_param("pmem_mdp_size", pmem_mdp_size_setup);
static unsigned pmem_adsp_size = MSM_PMEM_ADSP_SIZE;
static int __init pmem_adsp_size_setup(char *p)
{
pmem_adsp_size = memparse(p, NULL);
return 0;
}
early_param("pmem_adsp_size", pmem_adsp_size_setup);
static struct android_pmem_platform_data android_pmem_audio_pdata = {
.name = "pmem_audio", //给audio使用
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
.cached = 0,
.memory_type = MEMTYPE_EBI1,
};
static struct platform_device android_pmem_audio_device = {
.name = "android_pmem",
.id = 2,
.dev = { .platform_data = &android_pmem_audio_pdata },
};
static struct android_pmem_platform_data android_pmem_pdata = {
.name = "pmem", //给mdp使用,Quaclomm为啥不写成pmem_mdp?
.allocator_type = PMEM_ALLOCATORTYPE_BITMAP,
.cached = 1,
.memory_type = MEMTYPE_EBI1,
};
static struct platform_device android_pmem_device = {
.name = "android_pmem",
.id = 0,
.dev = { .platform_data = &android_pmem_pdata },
};
有了相应的platform_device之后,肯定要找到其platform_driver作设备匹配去。对应文件是pmem.c
static int __init pmem_init(void)
{
/*创建sysfs,位于/sys/kernel/ pmem_regions ,以每个PMEM模块的名字
命名,如pmem_audio。目录下的信息主要供用户空间查看当前PMEM模块的使用状况。*/
/* create /sys/kernel/<PMEM_SYSFS_DIR_NAME> directory */
pmem_kset = kset_create_and_add(PMEM_SYSFS_DIR_NAME,
NULL, kernel_kobj);
if (!pmem_kset) {
pr_err("pmem(%s):kset_create_and_add fail\n", __func__);
return -ENOMEM;
}
/*寻找platform device,接着调用pmem_probe */
return platform_driver_register(&pmem_driver);
}
static struct platform_driver pmem_driver = {
.probe = pmem_probe,
.remove = pmem_remove,
.driver = { .name = "android_pmem",
.pm = &pmem_dev_pm_ops,
}
};
static int pmem_probe(struct platform_device *pdev)
{
struct android_pmem_platform_data *pdata;
if (!pdev || !pdev->dev.platform_data) {
pr_alert("Unable to probe pmem!\n");
return -1;
}
pdata = pdev->dev.platform_data;
/*power manager相关,这里不关注。*/
pm_runtime_set_active(&pdev->dev);
pm_runtime_enable(&pdev->dev);
/*千呼万唤始出来,pmem初始化。*/
return pmem_setup(pdata, NULL, NULL);
}
Pmem_setup()此函数比较长,不过流程还是比较简单的。
int pmem_setup(struct android_pmem_platform_data *pdata,
long (*ioctl)(struct file *, unsigned int, unsigned long),
int (*release)(struct inode *, struct file *))
{
int i, index = 0, id;
struct vm_struct *pmem_vma = NULL;
struct page *page;
/*系统对设备总的pmem模块数量有限制。*/
if (id_count >= PMEM_MAX_DEVICES) {
pr_alert("pmem: %s: unable to register driver(%s) - no more "
"devices available!\n", __func__, pdata->name);
goto err_no_mem;
}
/*size为0表示在系统初始化的时候并没有预留一部分内存空间给此PMEM模块。如果这样肯定会申请失败的。*/
if (!pdata->size) {
pr_alert("pmem: %s: unable to register pmem driver(%s) - zero "
"size passed in!\n", __func__, pdata->name);
goto err_no_mem;
}
id = id_count++;
/*PMEM通过id来寻找对应的pmem模块*/
pmem[id].id = id;
/*表示已经分配过了。*/
if (pmem[id].allocate) {
pr_alert("pmem: %s: unable to register pmem driver - "
"duplicate registration of %s!\n",
__func__, pdata->name);
goto err_no_mem;
}
/*PMEM支持多种不同的allocate算法,在下面的switch case语句中可看到,本平台都使用默认的bitmap算法