Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3010835
  • 博文数量: 674
  • 博客积分: 17881
  • 博客等级: 上将
  • 技术积分: 4849
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-17 10:15
文章分类

全部博文(674)

文章存档

2013年(34)

2012年(146)

2011年(197)

2010年(297)

分类: LINUX

2010-06-11 21:44:46

 
Android PMEM主要有两个作用(来自android mail list):
  1. GPU or VPU buffers shared with CPU core
  2. Android service heap.
  其中1是不能cache的,2可以cache,平台设备注册中 cached = X即控制是否可以被cache。
  =======================================================================================
  简单看PMEM驱动,主要有以下内容:
  pmem_init()驱动加载
  |
  pmem_probe()platform加载
  |
  pmem_setup()
  初始化 pmem[id]
  启动时输出信息,格式为[名称][是否可以被cache] eg:pmem_adsp: 0 init
  misc_register()
  初始化所有的bitmap
  通过ioremap获取所有pmem[id].vbase
  pmem_map() 提供mmap接口
  pmem_ioctl()
  #define PMEM_GET_PHYS 获取物理地址
  #define PMEM_MAP pmem_remap()
  #define PMEM_GET_SIZE pmem_getsize()
  #define PMEM_UNMAP pmem_remap(®ion, file, PMEM_UNMAP);
  #define PMEM_ALLOCATE 分配pmem空间,len是参数,如果文件已被分配则失败
  #define PMEM_CONNECT 将一个pmem file与其他相连接
  #define PMEM_GET_TOTAL_SIZE 返回pmem region的全部尺寸
Android会使用Linux中的pmem driver进行内存分配。
通过代码的阅读,分配的关系我做了张简单的图。

说明:
1. pmem_probe
A. 获得设备的内存空间,包括物理地址和大小
B. 对空间的管理模块进行初始化,分区域
C. 对空间进行ioremap2. pmem_open
A. 创建新的pmem_data结构
B. 并使之与pmem[]建立链表关系
3. pmem_mmap
A. 根据mmap大小的需求,重新调整空间的管理模块。并从device中获得需要的空间
B. 为获得的区域重新建立页表
C. 如果是CONNECTED状态,需要对每个子区域从新建立页表
4. ioctl: PMEM_MAP
A. 确保map的可行性,获得map请求的区域
B. 创建新的region_node,将获得的区域信息保存到region_node中
C. 并与region_list建立链表关系
5. ioctl: PMEM_UNMAP
A. 从region_list移除请求的区域
B. 释放页表
6. ioctl: PMEM_CONNECT
A. 链接需要被connected的文件到当前文件。相当于两个文件映射到同一块区域。
7. ioctl: PMEM_ALLOCATE
A. 根据allocate大小的需求,重新调整空间的管理模块。并从device中获得需要的空间

下图例子,是pmem定义8M空间,而Android需要获得1M空间的状况。

  有篇文章值得参考
  =======================================================================================
  应用程序中使用PMEM,有待深入研究
  #include "android_pmem.h"
  int pmem_fd;
  void *pmem_base;
  unsigned int size;
  struct pmem_region region;
  pmem_fd = open("/dev/pmem_adsp", O_RDWR, 0);//打开设备,为了操作硬件引擎,要noncache的
  if (pmem_fd >= 0)
  {
  if (ioctl(pmem_fd, PMEM_GET_TOTAL_SIZE, ®ion) < 0) //获取全部空间
  {
  printf("PMEM_GET_TOTAL_SIZE failed ");

size = 4<<20; // 4 MiB
  }
  else
  {
  size = region.len;
  }
  pmem_base = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, pmem_fd, 0);//mmap操作
  if (pmem_base == MAP_FAILED)
  {
  pmem_base = 0;
  close(pmem_fd);
  pmem_fd = -1;
  printf("mmap pmem error! ");
  }
  if ( ioctl(pmem_fd, PMEM_GET_PHYS, ®ion) < 0)//获取物理地址
  {
  printf("PMEM_GET_PHYS failed ");
  }
  }
  其实第一个ioctl无用,只是为了获取长度,也可以自己指定长度。
  经过以上操作,region.offset为物理地址,其空间和虚拟地址pmem_base相对应。
  在程序中填充pmem_base数据,配置VPU、GPU时使用region.offset该物理地址。
  =======================================================================================
  最后来看看驱动调用流程
  1)open操作
  [drivers/misc/pmem.c:pmem_open:336] current 55 file c7355c80(1)
  2)mmap 会自动调用allocate
  [drivers/misc/pmem.c:pmem_allocate:398] order 0
  [drivers/misc/pmem.c:pmem_map_pfn_range:511] map offset 0 len 10000
  3)ioctl PMEM_GET_PHYS 感觉物理地址是根据pid来确定的
  [drivers/misc/pmem.c:pmem_ioctl:1081] get_phys
  pmem: request for physical address of pmem region from process 55.
  4)munmap
  [drivers/misc/pmem.c:pmem_vma_close:555] current 55 ppid 47 file c7355c80 count 2
 
 
阅读(2823) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~