平台:高通8X25
之前写的没写完!现在先贴出来作为学习笔记,防止时间长不见了。
Ion浅析
一个ion_handle 关联一个 ion_client和一个ion_buffer
一个ion_client关联多个ion_handle,以红黑树的数据结构进行管理,
同一个client通过不同的handle来标识不同的buffer.
一个ion_client关联一个ion_device
与client进行交互的数据结构是struct ion_handle_data {
struct ion_handle *handle;
};
也就是ion_handle数据结构体
以高通8X平台为例,从流程上来简单分析下ion驱动。
大致关系如图:
一.高通相关的ion:
1.实现方法
一般在board级别的文件中,会定义整个平台用到的几种heap.
这几种heap信息是以平台设备的形式和平台设备驱动关联起来的。
下面是设备的信息:(board-qrd7627a.c)
/**
* These heaps are listed in the order they will be allocated.
* Don't swap the order unless you know what you are doing!
*/
static struct ion_platform_data ion_pdata = {
.nr = MSM_ION_HEAP_NUM,
.has_outer_cache = 1,
.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 = ION_HEAP_TYPE_CARVEOUT,
.name = ION_CAMERA_HEAP_NAME,
.memory_type = ION_EBI_TYPE,
.extra_data = (void *)&co_ion_pdata,
},
/* PMEM_AUDIO */
{
.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,
},
#endif
}
};
static struct platform_device ion_dev = {
.name = "ion-msm",
.id = 1,
.dev = { .platform_data = &ion_pdata },
};
#endif
由上面可知,8X平台定义了四个heap.
分别是
ION_SYSTEM_HEAP_ID
ION_CAMERA_HEAP_ID
ION_AUDIO_HEAP_ID
ION_SF_HEAP_ID
此信息以平台设备的形式注册进platform驱动模型中。
下面是设备驱动的信息:(msm_ion.c)
设备驱动的注册结构体为:
static struct platform_driver msm_ion_driver = {
.probe = msm_ion_probe,
.remove = msm_ion_remove,
.driver = { .name = "ion-msm" }
};
具体平台设备和平台设备驱动是怎么关联的,此处就不进行分析,相关讲解比比皆是。
2.交互接口
QUACOMM ion的核心操作都是在 msm_ion_probe函数中。
函数主要功能:
{
ion_device_create();
1. 调用标准ion核心的接口注册ion设备文件
heaps[i] = ion_heap_create(heap_data);
2. msm_ion_heap_fixup(pdata->heaps, num_heaps);
此函数主要是为了创建heap的时候要求两个heap物理地址相连。方法是,申请一块大的内存块,然后将此内存块按照大小比例分成两块。这样两块heap在物理地址上就是相邻的
3. msm_ion_allocate(heap_data);
此函数式为一般的heap分配要求的内存空间
4. 根据board中定义的heap信息,创建平台的heap.
不同的heap类型拥有不同的管理方法
5. ion_device_add_heap(idev, heaps[i]);
此函数是heap添加进1中创建的dev中
6. check_for_heap_overlap(pdata->heaps, num_heaps);
检查heap之前是否有覆盖重叠的情况,如果有就发生panic
7. platform_set_drvdata(pdev, idev);
将创建的标准字符设备结构体作为平台设备的私有数据
}
自此,ion的heap信息已经注册完毕。
往后的问题就是client通过ion的设备文件与ion核心进行交互了。
3.小结
主要是将平台的几种heap信息注册进ion核心,并且创建调用Ion的接口,创建ion的设备文件。这样ion整套机制就可以工作起来了。
二.下面来顺一下client与ion核心的交互流程。
1.实现方法
通过#define ION_DEVICE "/dev/ion"设备文件。通过if(ioctl(iFd, ION_IOC_ALLOC, &ionAllocData)) 与内核进行交互。
有以下几种属性来标识与内核中哪一种heap进行交互。
enum {
GRALLOC_USAGE_PRIVATE_SYSTEM_HEAP = GRALLOC_USAGE_PRIVATE_0,
GRALLOC_USAGE_PRIVATE_UI_CONTIG_HEAP = GRALLOC_USAGE_PRIVATE_1,
GRALLOC_USAGE_PRIVATE_IOMMU_HEAP = GRALLOC_USAGE_PRIVATE_2,
GRALLOC_USAGE_PRIVATE_MM_HEAP = GRALLOC_USAGE_PRIVATE_3,
GRALLOC_USAGE_PRIVATE_CAMERA_HEAP = 0x01000000,
GRALLOC_USAGE_PRIVATE_UNCACHED = 0x02000000,
GRALLOC_USAGE_PRIVATE_UNSYNCHRONIZED = 0X04000000,
GRALLOC_USAGE_PRIVATE_EXTERNAL_ONLY = 0x08000000,
GRALLOC_USAGE_PRIVATE_EXTERNAL_BLOCK = 0x00100000,
GRALLOC_USAGE_PRIVATE_EXTERNAL_CC = 0x00200000,
GRALLOC_USAGE_PRIVATE_CP_BUFFER = 0x00400000,
GRALLOC_USAGE_PRIVATE_ADSP_HEAP = 0x0,
GRALLOC_USAGE_PRIVATE_SMI_HEAP = 0x0,
};
2,交互接口
设备文件对外的接口为:
static const struct file_operations ion_fops = {
.owner = THIS_MODULE,
.open = ion_open,
.release = ion_release,
.unlocked_ioctl = ion_ioctl,
};
概要介绍交互流程。
static int ion_open(struct inode *inode, struct file *file)
{
//每次open都创建一个cient结构体,用于记录用户的相关信息
client = ion_client_create(dev, -1, debug_name);
}
static int ion_release(struct inode *inode, struct file *file)
{
//在close设备文件的时候将创建的client信息消亡掉
ion_client_destroy(client);
}
其他的主要操作,都是通过ioctl接口进行操作的。下面进入主题。
static long ion_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
//与client之间进行信息传递是通过结构体
ion_allocation_data来实现的。
struct ion_allocation_data {
size_t len;//分配ffer的大小
size_t align;//对齐大小
unsigned int flags;//传递给heap的flag,目前不知道作何用处
struct ion_handle *handle;//核心信息都存储在此结构体中,里面记录着申请出的buffer的所有信息
};
//首先支持的集中command
1. ION_IOC_ALLOC
根据传递进来的信息,到对应的heap中分配一块期望大小的buffer
2. ION_IOC_FREE
释放之前申请的buffer
3. ION_IOC_MAP
4. ION_IOC_SHARE
目前理解不深入,表面上感觉是将已有的buffer变成DMA,用户控件通过此操作进行map,后获取对应的buffer地址
5. ION_IOC_IMPORT
此操作是将DMA导出,用于用户空间进程间的共享
6. ION_IOC_CUSTOM
7. ION_IOC_CLEAN_CACHES
8. ION_IOC_INV_CACHES
9. ION_IOC_CLEAN_INV_CACHES
这几个属性应该是缓存相关的操作,目前还不清楚用途
10. ION_IOC_GET_FLAGS
}
3.小结
三.Ion核心介绍
1.核心结构体介绍
struct ion_device {
//字符设备文件的文件节点信息
struct miscdevice dev;
//此设备所有的buffer信息,以红黑树的数据结构进行存储管理
struct rb_root buffers;
//一个互斥变量锁,应该是用于访问buffer或者heap用的吧,此处还不清楚
struct mutex lock;
//此设备关联的所有堆,此系统board文件中定义的信息。
struct rb_root heaps;
//不同平台自定义的一些ioctl操作
long (*custom_ioctl) (struct ion_client *client, unsigned int cmd,
unsigned long arg);
//所有访问此设备的client,也是以红黑树的结构进行存储管理
struct rb_root clients;
//用于DEBUG
struct dentry *debug_root;
};
struct ion_client {
//标识该client的节点,用于将自己添加进设备的全局client链表中去
struct rb_node node;
//此client对应的设备
struct ion_device *dev;
//与此client关联的所有hadle,目前理解是一种handle对应一种buffer
struct rb_root handles;
//互斥变量锁,此处不多说
struct mutex lock;
//此client不支持的heap信息
unsigned int heap_mask;
//client名字
char *name;
//此client所在进程的信息
struct task_struct *task;
//应该是进程的id信息吧
pid_t pid;
//用于debug调试
struct dentry *debug_root;
};
struct ion_handle {
//此属性应该是统计handle的引用计数的吧
struct kref ref;
//与handle关联的client
struct ion_client *client;
//与handle关联的buffer
struct ion_buffer *buffer;
//标识自己的节点,用于将自己添加进client的handle链表中去
struct rb_node node;
//此处不清楚,应该是kmap的次数?
unsigned int kmap_cnt;
//应该是iommu map的次数?
unsigned int iommu_map_cnt;
};
struct ion_buffer {
//标识此buffer的引用计数
struct kref ref;
//标识自己的节点,用于将自己添加进dev的buffer全局链表中去
struct rb_node node;
//buffer对应的设备文件节点
struct ion_device *dev;
//buffer属于的heap
struct ion_heap *heap;
//buffer的flag信息
unsigned long flags;
//buffer的大小
size_t size;
union {
//私有数据的存储类型,此处认为私有数据应该是地址吧?
void *priv_virt;
ion_phys_addr_t priv_phys;
};
//互斥变量锁
struct mutex lock;
//buffer被map进内核的次数
int kmap_cnt;
//如果内核map技术不为0,此处应该存储的是map地址
void *vaddr;
//buffer被map作为DMA的次数
int dmap_cnt;
//sg 表如果DMA map计数不为0
struct sg_table *sg_table;
int umap_cnt;
unsigned int iommu_map_cnt;
struct rb_root iommu_maps;
int marked;
};
struct ion_heap {
//标识自己的节点,用于将自己添加进dev的heap链表中去
struct rb_node node;
//对应的设备节点信息
struct ion_device *dev;
//heap的类型
enum ion_heap_type type;
//heap的管理接口
struct ion_heap_ops *ops;
//heap独一无二的id标识
int id;
//heap的名字
const char *name;
};
几者之间的关系:
一个ion_device关联所有的heap,所有的buffer,所有的client
一个ion_handle 关联一个 ion_client和一个ion_buffer
一个ion_client关联多个ion_handle,以红黑树的数据结构进行管理,
同一个client通过不同的handle来标识不同的buffer.
一个ion_client关联一个ion_device
与client进行交互的数据结构是struct ion_handle_data {
struct ion_handle *handle;
};
也就是ion_handle数据结构体
1.1个ion_device对应all ion_buffer
2.1个ion_buffer对应1个ion_device
3. 1个ion_device对应all ion_client
4. 1个ion_client对应1个ion_device
5. 1个ion_device对应 all ion_heap
6. 1个ion_heap对应1个ion_device
7. 1个ion_client对应多个ion_handle
8.1个ion_handle对应1个ion_client
9.1个ion_buffer对应1个ion_heap
10.1个ion_buffer对应1个on_handle
Heap类型:
enum ion_heap_type {
//内存申请通过vmalloc
ION_HEAP_TYPE_SYSTEM,
//内存申请通过kmalloc
ION_HEAP_TYPE_SYSTEM_CONTIG,
//从一个保留区域中申请内存,申请的内存在物理上面是连续的
ION_HEAP_TYPE_CARVEOUT,
//申请的内存来自IO地址空间
ION_HEAP_TYPE_IOMMU,
//从一个保留区域中申请内存,申请的内存在物理上面是连续的,此内存用于内容保护
ION_HEAP_TYPE_CP,
//用户自定义的,目前没有用到
ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always
are at the end of this enum */
ION_NUM_HEAPS,
};
几种用到的heap
enum ion_heap_ids {
INVALID_HEAP_ID = -1,
ION_CP_MM_HEAP_ID = 8,
ION_CP_MFC_HEAP_ID = 12,
ION_CP_WB_HEAP_ID = 16, /* 8660 only */
ION_CAMERA_HEAP_ID = 20, /* 8660 only */
ION_SF_HEAP_ID = 24,
ION_IOMMU_HEAP_ID = 25,
ION_QSECOM_HEAP_ID = 27,
ION_AUDIO_HEAP_ID = 28,
ION_MM_FIRMWARE_HEAP_ID = 29,
ION_SYSTEM_HEAP_ID = 30,
ION_HEAP_ID_RESERVED = 31 /** Bit reserved for ION_SECURE flag */
};
不同类型的heap都有共同需要实现的回调函数。但是管理方式不一样。
通用实现的接口:
struct ion_heap_ops {
int (*allocate) (struct ion_heap *heap,
struct ion_buffer *buffer, unsigned long len,
unsigned long align, unsigned long flags);
void (*free) (struct ion_buffer *buffer);
int (*phys) (struct ion_heap *heap, struct ion_buffer *buffer,
ion_phys_addr_t *addr, size_t *len);
struct sg_table *(*map_dma) (struct ion_heap *heap,
struct ion_buffer *buffer);
void (*unmap_dma) (struct ion_heap *heap, struct ion_buffer *buffer);
void * (*map_kernel) (struct ion_heap *heap, struct ion_buffer *buffer);
void (*unmap_kernel) (struct ion_heap *heap, struct ion_buffer *buffer);
int (*map_user) (struct ion_heap *mapper, struct ion_buffer *buffer,
struct vm_area_struct *vma);
void (*unmap_user) (struct ion_heap *mapper, struct ion_buffer *buffer);
int (*cache_op)(struct ion_heap *heap, struct ion_buffer *buffer,
void *vaddr, unsigned int offset,
unsigned int length, unsigned int cmd);
int (*map_iommu)(struct ion_buffer *buffer,
struct ion_iommu_map *map_data,
unsigned int domain_num,
unsigned int partition_num,
unsigned long align,
unsigned long iova_length,
unsigned long flags);
void (*unmap_iommu)(struct ion_iommu_map *data);
int (*print_debug)(struct ion_heap *heap, struct seq_file *s,
const struct rb_root *mem_map);
int (*secure_heap)(struct ion_heap *heap, int version, void *data);
int (*unsecure_heap)(struct ion_heap *heap, int version, void *data);
};
根据不同的heap类型来实例化不同的管理方式.
struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
{
struct ion_heap *heap = NULL;
switch (heap_data->type) {
case ION_HEAP_TYPE_SYSTEM_CONTIG:
heap = ion_system_contig_heap_create(heap_data);
{
heap->ops = &kmalloc_ops;
heap->type = ION_HEAP_TYPE_SYSTEM_CONTIG;
}
break;
case ION_HEAP_TYPE_SYSTEM:
heap = ion_system_heap_create(heap_data);
{
heap->ops = &vmalloc_ops;
heap->type = ION_HEAP_TYPE_SYSTEM;
}
break;
case ION_HEAP_TYPE_CARVEOUT:
heap = ion_carveout_heap_create(heap_data);
{
carveout_heap->heap.ops = &carveout_heap_ops;
carveout_heap->heap.type = ION_HEAP_TYPE_CARVEOUT;
}
break;
case ION_HEAP_TYPE_IOMMU:
heap = ion_iommu_heap_create(heap_data);
{
iommu_heap->heap.ops = &iommu_heap_ops;
iommu_heap->heap.type = ION_HEAP_TYPE_IOMMU;
}
break;
case ION_HEAP_TYPE_CP:
heap = ion_cp_heap_create(heap_data);
{
cp_heap->heap.ops = &cp_heap_ops;
cp_heap->heap.type = ION_HEAP_TYPE_CP;
}
break;
default:
pr_err("%s: Invalid heap type %d\n", __func__,
heap_data->type);
return ERR_PTR(-EINVAL);
}
if (IS_ERR_OR_NULL(heap)) {
pr_err("%s: error creating heap %s type %d base %lu size %u\n",
__func__, heap_data->name, heap_data->type,
heap_data->base, heap_data->size);
return ERR_PTR(-EINVAL);
}
heap->name = heap_data->name;
heap->id = heap_data->id;
return heap;
}