ION框架學習(一)

第一章介紹:ION的框架和buffer的分配;
第二章介紹:如何使用ION buffer;

  ION是google在Android4.0 爲了解決內存碎片管理而引入的通用內存管理器,用來支持不同的內存分配機制,如CARVOUT(PMEM),物理連續內存(kmalloc), 虛擬地址連續但物理不連續內存(vmalloc), IOMMU等


(一)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表示。

  下面是整個框架的類圖:

這裏寫圖片描述

說明如下:

  1. 在driver初始化過程中會創建ion_device,並提供給用戶層ioctrl接口;不同平臺根據定義好的platform data heap類型創建heap,同時指定這寫heap操作使用的方法接口;不同類型的heap連接成鏈表,保存在通過plist_head heap;

  2. 需要使用heap,先註冊client,不同的heap有多個client來使用,連接成鏈表保存在rb_root client;不同的client跟不同的進程pid綁定;

  3. ion_handle管理實際ion_buffer, 成員id:唯一表示ion_buffer的整型變量,通過內核的idr機制加上這個id就可以在其它進程中訪問到這塊buffer。而且上層在傳下來的struct ion_allocation_data結構體中也只是保存了這個id。


  用戶空間和內核空間都可以成爲client,不過創建的方法稍稍有點區別;

  1. 內核空間:先創建client,有了client之後就可以分配內存,有了handle也就是buffer之後就準備使用了,不過還是物理地址,需要map:

  2. 用戶空間:用戶空間如果想使用ION,也必須先要創建client,不過它是打開/dev/ion,實際上它最終也會調用ion_client_create。不過和內核空間創建client的一點區別是,用戶空間不能選擇heap type(使用預訂的heap id隱含heap type),但是內核空間卻可以。另外,用戶空間是通過IOCTL來分配內存的,cmd爲ION_IOC_ALLOC.

    ion_fd = open("/dev/ion", O_ RDONLY | O_SYNC);   
    ioctl(ion_fd, ION_IOC_ALLOC, alloc);  

  分配好了buffer之後,如果用戶空間想使用buffer,先需要mmap. ION是通過先調用IOCTL中的ION_IOC_SHARE/ION_IOC_MAP來得到可以mmap的fd,然後再執行mmap得到buffer address.然後你也可以將此fd傳給另一個進程,如通過binder傳遞。在另一個進程中通過ION_IOC_IMPORT這個IOCTL來得到這塊共享buffer了。


(二)ION Device和Heap創建

  通過ION device和driver匹配之後走入ion_drv_probe()函數:

kernel-4.4/drivers/staging/android/ion/mtk/ion_drv.c

686 static int ion_drv_probe(struct platform_device *pdev)
        //創建ion device,name爲ion,並提供應用層操作接口ion_fops;創建調試節點:/sys/kernel/debug/ion
693     g_ion_device = ion_device_create(ion_custom_ioctl);
       //ion_custom_ioctl soc自定義的ioctl操作;
698 
699     /* create the heaps as specified in the board file */
700     for (i = 0; i < num_heaps; i++) {
701         struct ion_platform_heap *heap_data = &pdata->heaps[i];
702         struct ion_heap *heap;
703 
704         if (heap_data->type == ION_HEAP_TYPE_CARVEOUT && heap_data->base == 0) {
705             /* reserve for carveout heap failed */
706             heap_data->size = 0;
707             continue;
708         }
709 
710         heap = ion_mtk_heap_create(heap_data);
714 
715         ion_device_add_heap(g_ion_device, heap);
716     }

  這個函數首先創建一個設備ion_device,通過ion_device_create()來創建,傳入一個給到用戶層面用的ioctl函數:

539 static long _ion_ioctl(struct ion_client *client, unsigned int cmd,
540                unsigned long arg, int from_kernel) {
541     long ret = 0;
542 
543     ION_FUNC_ENTER;
544     switch (cmd) {
545     case ION_CMD_SYSTEM:
546         ret = ion_sys_ioctl(client, cmd, arg, from_kernel);
547         break;
548     case ION_CMD_MULTIMEDIA:
549         ret = ion_mm_ioctl(client, cmd, arg, from_kernel);
550         break;
551     }                                                                                                                                      
552     ION_FUNC_LEAVE;
553     return ret;
554 }

  處理的ioctrl命令有:

 30 enum ION_MM_CMDS {
 31     ION_MM_CONFIG_BUFFER,                                                                                                                  
 32     ION_MM_SET_DEBUG_INFO,      
 33     ION_MM_GET_DEBUG_INFO,
 34     ION_MM_SET_SF_BUF_INFO,
 35     ION_MM_GET_SF_BUF_INFO,
 36     ION_MM_CONFIG_BUFFER_EXT
 37 };           
 38 
 39 enum ION_SYS_CMDS { 
 40     ION_SYS_CACHE_SYNC,
 41     ION_SYS_GET_PHYS,
 42     ION_SYS_GET_CLIENT, 
 43     ION_SYS_SET_HANDLE_BACKTRACE,
 44     ION_SYS_SET_CLIENT_NAME,
 45     ION_SYS_DMA_OP, 
 46 };

  不同的平臺實現這些方式不一樣,然後根據ion_platform_data表示平臺定義的各種類型的heap數據類型來分配heap,以高通平臺是定義在dts裏面,mtk平臺定義在驅動當中,舉例如下:

742 static struct ion_platform_heap ion_drv_platform_heaps[] = {
743         {
744                 .type = ION_HEAP_TYPE_SYSTEM_CONTIG,
745                 .id = ION_HEAP_TYPE_SYSTEM_CONTIG,
746                 .name = "ion_system_contig_heap",
747                 .base = 0,
748                 .size = 0,
749                 .align = 0,
750                 .priv = NULL,
751         },
752         {
753                 .type = ION_HEAP_TYPE_MULTIMEDIA,
754                 .id = ION_HEAP_TYPE_MULTIMEDIA,
755                 .name = "ion_mm_heap",
756                 .base = 0,
757                 .size = 0,
758                 .align = 0,
759                 .priv = NULL,
760         },
761         {
762                 .type = ION_HEAP_TYPE_MULTIMEDIA,
763                 .id = ION_HEAP_TYPE_MULTIMEDIA_FOR_CAMERA,
764                 .name = "ion_mm_heap_for_camera",
765                 .base = 0,
766                 .size = 0,
767                 .align = 0,
768                 .priv = NULL,
769         },

  根據ion_platform_data定義的heap類型然後接下來分配ion heap結構,不同的heap類型代表不同的分配方式:

 37 enum ion_heap_type {                                                                                                                       
 38     ION_HEAP_TYPE_SYSTEM, //通過vmalloc分配內存;
 39     ION_HEAP_TYPE_SYSTEM_CONTIG, //通過kmalloc分配內存;
 40     ION_HEAP_TYPE_CARVEOUT, //在保留內存塊中(reserve memory)分配內存;
 41     ION_HEAP_TYPE_CHUNK, //模塊;
 42     ION_HEAP_TYPE_DMA,
 43     ION_HEAP_TYPE_CUSTOM, //由客戶自己定義
 47     ION_NUM_HEAPS = 16,
 48 };

  mtk平臺又根據heap data存儲的數據對象分爲:

 19 enum mtk_ion_heap_type {
 20     ION_HEAP_TYPE_MULTIMEDIA = 10,
 21     ION_HEAP_TYPE_FB = 11,
 22     ION_HEAP_TYPE_MULTIMEDIA_FOR_CAMERA = 12,
 23     ION_HEAP_TYPE_MULTIMEDIA_SEC = 13,
 24     ION_HEAP_TYPE_MULTIMEDIA_MAP_MVA = 14,
 25     ION_HEAP_TYPE_MULTIMEDIA_PA2MVA = 15,
 27 };

  以ION_HEAP_TYPE_MULTIMEDIA數據類型爲例,heap的創建最後通過ion_mm_heap_create()實現:

//不同type的heap需要不同的method去分配,不過都是用struct ion_heap_ops來表示;
 537 static struct ion_heap_ops system_heap_ops = {
 538         .allocate = ion_mm_heap_allocate,
 539         .free = ion_mm_heap_free,
 540         .map_dma = ion_mm_heap_map_dma,//map the memory for dma to a scatterlist;
 541         .unmap_dma = ion_mm_heap_unmap_dma,
 542         .map_kernel = ion_heap_map_kernel,//map memory to the kernel;
 543         .unmap_kernel = ion_heap_unmap_kernel,
 544         .map_user = ion_heap_map_user,
 545         .phys = ion_mm_heap_phys,//get physical address of a buffer;
 546         .shrink = ion_mm_heap_shrink,
 547         .page_pool_total = ion_mm_heap_pool_total,
 548 };

 static const unsigned int orders[] = { 1, 0 };  //兩個內存池,爲別爲2^1k和2^0k;

 799 struct ion_heap *ion_mm_heap_create(struct ion_platform_heap *unused)
 800 {                                                                                                                                         
 801     struct ion_system_heap *heap;
 802     int i;
 803 
 804     heap = kzalloc(sizeof(*heap), GFP_KERNEL);
 805     if (!heap) {
 806         IONMSG("%s kzalloc failed heap is null.\n", __func__);
 807         return ERR_PTR(-ENOMEM);
 808     }
 809     heap->heap.ops = &system_heap_ops;
 810     heap->heap.type = ION_HEAP_TYPE_MULTIMEDIA;
 811     heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
 812     heap->pools = kcalloc(num_orders, sizeof(struct ion_page_pool *), GFP_KERNEL);
 813     if (!heap->pools)
 814         goto err_alloc_pools;
 815     heap->cached_pools = kcalloc(num_orders, sizeof(struct ion_page_pool *), GFP_KERNEL);
 816     if (!heap->cached_pools) {
 817         kfree(heap->pools);
 818         goto err_alloc_pools;
 819     }
 820     //創建兩種大小類型的pool,後面的alloc就會根據order在這裏面分配;
 821     for (i = 0; i < num_orders; i++) {
 822         struct ion_page_pool *pool;
 823         gfp_t gfp_flags = low_order_gfp_flags;
 824 
 825         if (orders[i] > 0)
 826             gfp_flags = high_order_gfp_flags;
 827 
 828         if (unused->id == ION_HEAP_TYPE_MULTIMEDIA_FOR_CAMERA)
 829             gfp_flags |= __GFP_HIGHMEM | __GFP_MOVABLE;
  831         pool = ion_page_pool_create(gfp_flags, orders[i]);//主要初始化這個pool;
 832         if (!pool)
 833             goto err_create_pool;
 834         heap->pools[i] = pool;
 835 
 836         pool = ion_page_pool_create(gfp_flags, orders[i]);
 837         if (!pool)
 838             goto err_create_pool;
 839         heap->cached_pools[i] = pool;
 840     } 
 860 }

169 struct ion_page_pool *ion_page_pool_create(gfp_t gfp_mask, unsigned int order)
170 {                                                                                                                                          
171     struct ion_page_pool *pool = kmalloc(sizeof(struct ion_page_pool),
172                          GFP_KERNEL); 
173     if (!pool) {
174         IONMSG("%s kmalloc failed pool is null.\n", __func__);
175         return NULL;
176     }
177     pool->high_count = 0;
178     pool->low_count = 0; 
179     INIT_LIST_HEAD(&pool->low_items); //每一個pool都包含了高地址和低地址的雙向鏈表;
180     INIT_LIST_HEAD(&pool->high_items);
181     pool->gfp_mask = gfp_mask | __GFP_COMP;
182     pool->order = order;
183     mutex_init(&pool->mutex);
184     plist_node_init(&pool->list, order);
185 
186     return pool;
187 }


(三)添加ION client

  內核和用戶空間都會可以創建ion client,用戶空間open ion設備來創建client,MTK封裝了一層mt_ion_open(),最終調用ion_client_create()來創建;區別在與用戶層創建的name是根據pid:

5693         pIon_client = ion_client_create(g_ion_device, "camera_isp"); 
kernel-4.4/drivers/staging/android/ion/ion.c:

826 struct ion_client *ion_client_create(struct ion_device *dev,
 827                      const char *name)
 828 {                                                                                                                                         
 829     struct ion_client *client;
 830     struct task_struct *task;
 831     struct rb_node **p;
 832     struct rb_node *parent = NULL;
 833     struct ion_client *entry;
 834     pid_t pid;
 835 
 841     get_task_struct(current->group_leader);
 842     task_lock(current->group_leader);
 843     pid = task_pid_nr(current->group_leader);
 848     if (current->group_leader->flags & PF_KTHREAD) {
 849         put_task_struct(current->group_leader);
 850         task = NULL;
 851     } else {
 852         task = current->group_leader;
 853     }
 854     task_unlock(current->group_leader);
 855 
 856     client = kzalloc(sizeof(struct ion_client), GFP_KERNEL);
 857     if (!client)
858         goto err_put_task_struct;
 859 
 860     client->dev = dev;
 861     client->handles = RB_ROOT;
 862     idr_init(&client->idr);
 863     mutex_init(&client->lock);
 864     client->task = task;
 865     client->pid = pid;
 866     client->name = kstrdup(name, GFP_KERNEL);
 867     if (!client->name)
 868         goto err_free_client;
 869 
 870     down_write(&dev->lock);
 871     client->display_serial = ion_get_client_serial(&dev->clients, name);
 872     client->display_name = kasprintf(
 873         GFP_KERNEL, "%s-%d", name, client->display_serial);
 874     if (!client->display_name) {
 875         up_write(&dev->lock);
 876         goto err_free_client_name;
 877     }
    //把該clinet放到ion device的紅黑樹列表裏面;
 878     p = &dev->clients.rb_node;
 879     while (*p) {
 880         parent = *p;
 881         entry = rb_entry(parent, struct ion_client, node);
 882 
 883         if (client < entry)
 884             p = &(*p)->rb_left;
 885         else if (client > entry)
 886             p = &(*p)->rb_right;
 887     }
 888     rb_link_node(&client->node, parent, p);
 889     rb_insert_color(&client->node, &dev->clients);
 890 
 891     client->debug_root = debugfs_create_file(client->display_name, 0664,
 892                         dev->clients_debug_root,
 893                         client, &debug_client_fops);
 894     if (!client->debug_root) {
 895         char buf[256], *path;
 896 
 897         path = dentry_path(dev->clients_debug_root, buf, 256);
 898         pr_err("Failed to create client debugfs at %s/%s\n",
 899             path, client->display_name);
 900     }
 901 
 902     up_write(&dev->lock);
 903 
 904     return client;
 905 
 914 }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章