android 之ion

平台:高通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整套机制就可以工作起来了。

二.下面来顺一下cliention核心的交互流程。

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;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值