ION 概念

ION是Google的下一代内存管理器,用来支持不同的内存分配机制,如CARVOUT,物理连续内存(kmalloc), 虚拟地址连续但物理不连续内存(vmalloc), IOMMU等。

用户空间和内核空间都可以使用ION,用户空间是通过/dev/ion来创建client的。

说到client, 顺便看下ION相关比较重要的几个概念。

Heap: 用来表示内存分配的相关信息,包括id, type, name等。用struct ion_heap表示。

Client: Ion的使用者,用户空间和内核控件要使用ION的buffer,必须先创建一个client,一个client可以有多个buffer,用struct ion_buffer表示。

Handle: 将buffer该抽象出来,可以认为ION用handle来管理buffer,一般用户直接拿到的是handle,而不是buffer。 用struct ion_handle表示。

heap类型:

由于ION可以使用多种memory分配机制,例如物理连续和不连续的,所以ION使用enum ion_heap_type表示。
/** 
 * enum ion_heap_types - list of all possible types of heaps 
 * @ION_HEAP_TYPE_SYSTEM:    memory allocated via vmalloc 
 * @ION_HEAP_TYPE_SYSTEM_CONTIG: memory allocated via kmalloc 
 * @ION_HEAP_TYPE_CARVEOUT:  memory allocated from a prereserved carveout heap, allocations are physically contiguous 
 * @ION_HEAP_TYPE_IOMMU: IOMMU memory 
 * @ION_HEAP_TYPE_CP: memory allocated from a prereserved carveout heap, allocations are physically contiguous. Used for content protection. 
 * @ION_HEAP_TYPE_DMA:  memory allocated via DMA API 
 * @ION_HEAP_END:       helper for iterating over heaps 
 */  
enum ion_heap_type {  
    ION_HEAP_TYPE_SYSTEM,  
    ION_HEAP_TYPE_SYSTEM_CONTIG,  
    ION_HEAP_TYPE_CARVEOUT,  
    ION_HEAP_TYPE_IOMMU,  
    ION_HEAP_TYPE_CP,  
    ION_HEAP_TYPE_DMA,  
    ION_HEAP_TYPE_CUSTOM, /* must be last so device specific heaps always are at the end of this enum */  
    ION_NUM_HEAPS,  
};                                                                                                                                 代码中的注释很明确地说明了哪种type对应的是分配哪种memory。不同type的heap需要不同的method去分配,不过都是用struct ion_heap_ops来表示的。如以下例子:
static struct ion_heap_ops carveout_heap_ops = {  
    .allocate = ion_carveout_heap_allocate,  
    .free = ion_carveout_heap_free,  
    .phys = ion_carveout_heap_phys,  
    .map_user = ion_carveout_heap_map_user,  
    .map_kernel = ion_carveout_heap_map_kernel,  
    .unmap_user = ion_carveout_heap_unmap_user,  
    .unmap_kernel = ion_carveout_heap_unmap_kernel,  
    .map_dma = ion_carveout_heap_map_dma,  
    .unmap_dma = ion_carveout_heap_unmap_dma,  
    .cache_op = ion_carveout_cache_ops,  
    .print_debug = ion_carveout_print_debug,  
    .map_iommu = ion_carveout_heap_map_iommu,  
    .unmap_iommu = ion_carveout_heap_unmap_iommu,  
};  
  
static struct ion_heap_ops kmalloc_ops = {  
    .allocate = ion_system_contig_heap_allocate,  
    .free = ion_system_contig_heap_free,  
    .phys = ion_system_contig_heap_phys,  
    .map_dma = ion_system_contig_heap_map_dma,  
    .unmap_dma = ion_system_heap_unmap_dma,  
    .map_kernel = ion_system_heap_map_kernel,  
    .unmap_kernel = ion_system_heap_unmap_kernel,  
    .map_user = ion_system_contig_heap_map_user,  
    .cache_op = ion_system_contig_heap_cache_ops,  
    .print_debug = ion_system_contig_print_debug,  
    .map_iommu = ion_system_contig_heap_map_iommu,  
    .unmap_iommu = ion_system_heap_unmap_iommu,  
};  

Heap ID:

同一种type的heap上当然可以分为若该干个chunk供用户使用,所以ION又使用ID来区分了。例如在type为ION_HEAP_TYPE_CARVEOUT的heap上,audio和display部分都需要使用,ION就用ID来区分。

Heap id用enumion_heap_ids表示。
/** 
 * These are the only ids that should be used for Ion heap ids. 
 * The ids listed are the order in which allocation will be attempted 
 * if specified. Don't swap the order of heap ids unless you know what you are doing! 
 * Id's are spaced by purpose to allow new Id's to be inserted in-between (for possible fallbacks) 
 */  
  
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 = 26,  
    ION_AUDIO_HEAP_BL_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 定义:

       了解了heaptype和id,看看如何被用到了,本平台使用的文件为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! 
 */  
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  
};  


ION Handle:

当Ion client分配buffer时,相应的一个唯一的handle也会被指定,当然client可以多次申请ion buffer。申请好buffer之后,返回的是一个ion handle, 不过要知道Ion buffer才和实际的内存相关,包括size, address等信息。Struct ion_handle和struct ion_buffer如下:


/** 
 * ion_handle - a client local reference to a buffer 
 * @ref:        reference count 
 * @client:     back pointer to the client the buffer resides in 
 * @buffer:     pointer to the buffer 
 * @node:       node in the client's handle rbtree 
 * @kmap_cnt:       count of times this client has mapped to kernel 
 * @dmap_cnt:       count of times this client has mapped for dma 
 * 
 * Modifications to node, map_cnt or mapping should be protected by the 
 * lock in the client.  Other fields are never changed after initialization. 
 */  
struct ion_handle {  
    struct kref ref;  
    struct ion_client *client;  
    struct ion_buffer *buffer;  
    struct rb_node node;  
    unsigned int kmap_cnt;  
    unsigned int iommu_map_cnt;  
};  
  
/** 
 * struct ion_buffer - metadata for a particular buffer 
 * @ref:        refernce count 
 * @node:       node in the ion_device buffers tree 
 * @dev:        back pointer to the ion_device 
 * @heap:       back pointer to the heap the buffer came from 
 * @flags:      buffer specific flags 
 * @size:       size of the buffer 
 * @priv_virt:      private data to the buffer representable as a void * 
 * @priv_phys:      private data to the buffer representable as an ion_phys_addr_t (and someday a phys_addr_t) 
 * @lock:       protects the buffers cnt fields 
 * @kmap_cnt:       number of times the buffer is mapped to the kernel 
 * @vaddr:      the kenrel mapping if kmap_cnt is not zero 
 * @dmap_cnt:       number of times the buffer is mapped for dma 
 * @sg_table:       the sg table for the buffer if dmap_cnt is not zero 
*/  
struct ion_buffer {  
    struct kref ref;  
    struct rb_node node;  
    struct ion_device *dev;  
    struct ion_heap *heap;  
    unsigned long flags;  
    size_t size;  
    union {  
        void *priv_virt;  
        ion_phys_addr_t priv_phys;  
    };  
    struct mutex lock;  
    int kmap_cnt;  
    void *vaddr;  
    int dmap_cnt;  
    struct sg_table *sg_table;  
    int umap_cnt;  
    unsigned int iommu_map_cnt;  
    struct rb_root iommu_maps;  
    int marked;  
};  

ION APIs
用户空间 API
定义了6种 ioctl 接口,可以与用户应用程序交互。
ION_IOC_ALLOC: 分配内存
ION_IOC_FREE: 释放内存
ION_IOC_MAP: 获取文件描述符进行mmap  (? 在code中未使用这个定义)
ION_IOC_SHARE: 创建文件描述符来实现共享内存
ION_IOC_IMPORT: 获取文件描述符
ION_IOC_CUSTOM: 调用用户自定义的ioctl
ION_IOC_SHARE 及ION_IOC_IMPORT是基于DMABUF实现的,所以当共享进程获取文件描述符后,可以直接调用mmap来操作共享内存。mmap实现由DMABUF子系统调用ION子系统中mmap回调函数完成。
内核空间 API
内核驱动也可以注册为一个ION的客户端(client),可以选择使用哪种类型的heap来申请内存。
ion_client_create: 分配一个客户端。
ion_client_destroy: 释放一个客户端及绑定在它上面的所有ion handle.
ion handle: 这里每个ion handle映射到一个buffer中,每个buffer关联一个heap。也就是说一个客户端可以操作多块buffer。
Buffer 申请及释放函数:
ion_alloc: 申请ion内存,返回ion handle
ion_free: 释放ion handle
ION 通过handle来管理buffer,驱动需要可以访问到buffer的地址。ION通过下面的函数来达到这个目的
ion_phys: 返回buffer的物理地址(address)及大小(size)
ion_map_kernel: 给指定的buffer创建内核内存映射
ion_unmap_kernel: 销毁指定buffer的内核内存映射
ion_map_dma: 为指定buffer创建dma 映射,返回sglist(scatter/gather list)
ion_unmap_dma: 销毁指定buffer的dma映射
ION是通过handle而非buffer地址来实现驱动间共享内存,用户空间共享内存也是利用同样原理。
ion_share: given a handle, obtain a buffer to pass to other clients
ion_import: given an buffer in another client, import it
ion_import_fd: given an fd obtained via ION_IOC_SHARE ioctl, import it
Heap API
Heap 接口定义 [drivers/gpu/ion/ion_priv.h]
这些接口不是暴露给驱动或者用户应用程序的。
/**
 * struct ion_heap_ops - ops to operate on a given heap
 * @allocate:           allocate memory
 * @free:               free memory
 * @phys                get physical address of a buffer (only define on physically contiguous heaps)
 * @map_dma             map the memory for dma to a scatterlist
 * @unmap_dma           unmap the memory for dma
 * @map_kernel          map memory to the kernel
 * @unmap_kernel        unmap memory to the kernel
 * @map_user            map memory to userspace
 */
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 scatterlist *(*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);
};
ION debug
ION 在/sys/kernel/debug/ion/ 提供一个debugfs 接口。
每个heap都有自己的debugfs目录,client内存使用状况显示在/sys/kernel/debug/ion/<<heap name>>
$cat /sys/kernel/debug/ion/ion-heap-1 
          client              pid             size
        test_ion             2890            16384
每个由pid标识的client也有一个debugfs目录/sys/kernel/debug/ion/<<pid>>
$cat /sys/kernel/debug/ion/2890 
       heap_name:    size_in_bytes
      ion-heap-1:    40960 11





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值