From 9926e4c0c57078164c94a545fcb70abe837916c2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E9=99=88=E6=81=92=E6=98=8E?= Date: Wed, 14 Mar 2012 17:14:28 +0800 Subject: [PATCH] rk29: vpu_mem: add pool interface to limit vpu_mem usage --- arch/arm/mach-rk29/include/mach/vpu_mem.h | 4 +- arch/arm/mach-rk29/vpu_mem.c | 834 +++++++++++++--------- 2 files changed, 519 insertions(+), 319 deletions(-) diff --git a/arch/arm/mach-rk29/include/mach/vpu_mem.h b/arch/arm/mach-rk29/include/mach/vpu_mem.h index 7d4c5279ef7b..40faef3c368d 100644 --- a/arch/arm/mach-rk29/include/mach/vpu_mem.h +++ b/arch/arm/mach-rk29/include/mach/vpu_mem.h @@ -28,7 +28,9 @@ #define VPU_MEM_LINK _IOW(VPU_MEM_IOCTL_MAGIC, 7, unsigned int) #define VPU_MEM_CACHE_CLEAN _IOW(VPU_MEM_IOCTL_MAGIC, 8, unsigned int) #define VPU_MEM_CACHE_INVALID _IOW(VPU_MEM_IOCTL_MAGIC, 9, unsigned int) - +#define VPU_MEM_POOL_SET _IOW(VPU_MEM_IOCTL_MAGIC, 10, unsigned int) +#define VPU_MEM_POOL_UNSET _IOW(VPU_MEM_IOCTL_MAGIC, 11, unsigned int) +#define VPU_MEM_POOL_CHECK _IOW(VPU_MEM_IOCTL_MAGIC, 12, unsigned int) struct vpu_mem_platform_data { diff --git a/arch/arm/mach-rk29/vpu_mem.c b/arch/arm/mach-rk29/vpu_mem.c index bc05e6842ea4..d5ce57e43ac7 100644 --- a/arch/arm/mach-rk29/vpu_mem.c +++ b/arch/arm/mach-rk29/vpu_mem.c @@ -51,24 +51,47 @@ * @author ChenHengming (2011-4-11) */ typedef struct vpu_mem_session { - /* a list of memory region used posted by current process */ - struct list_head list_used; - struct list_head list_post; - /* a linked list of data so we can access them for debugging */ - struct list_head list_session; + /* a list of memory region used posted by current process */ + struct list_head list_used; + struct list_head list_post; + /* a linked list of data so we can access them for debugging */ + struct list_head list_session; + /* a linked list of memory pool on current session */ + struct list_head list_pool; /* process id of teh mapping process */ pid_t pid; } vdm_session; +/** + * session memory pool info + */ +typedef struct vpu_mem_pool_info { + struct list_head session_link; /* link to session use for search */ + struct list_head list_used; /* a linked list for used memory in the pool */ + vdm_session *session; + int count_current; + int count_target; + int count_used; + int pfn; +} vdm_pool; + +/** + * session memory pool config input + */ +typedef struct vpu_mem_pool_config { + int size; + unsigned int count; +} vdm_pool_config; + /** * global region info */ typedef struct vpu_mem_region_info { - struct list_head index_list; /* link to index list use for search */ - int used; - int post; - int index; - int pfn; + struct list_head index_list; /* link to index list use for search */ + int used; + int post; + int index; + int pfn; } vdm_region; /** @@ -76,13 +99,19 @@ typedef struct vpu_mem_region_info { * this struct should be modified with bitmap lock */ typedef struct vpu_mem_link_info { - struct list_head session_link; /* link to vpu_mem_session list */ - struct list_head status_link; /* link to vdm_info.status list use for search */ - vdm_region *region; - int link_post; - int link_used; - int index; - int pfn; + struct list_head session_link; /* link to vpu_mem_session list */ + struct list_head status_link; /* link to vdm_info.status list use for search */ + struct list_head pool_link; /* link to vpu_mem_session pool list for search */ + vdm_region *region; + vdm_pool *pool; + union { + int post; + int used; + int count; + } ref; + int *ref_ptr; + int index; + int pfn; } vdm_link; /** @@ -106,11 +135,11 @@ typedef struct vpu_mem_info { /* * vdm_session init only store the free region but use a vdm_session for convenience */ - vdm_session status; + vdm_session status; struct list_head list_index; /* sort by index */ - struct list_head list_free; /* free region list */ - struct list_head list_session; /* session list */ - struct rw_semaphore rw_sem; + struct list_head list_free; /* free region list */ + struct list_head list_session; /* session list */ + struct rw_semaphore rw_sem; } vdm_info; static vdm_info vpu_mem; @@ -133,47 +162,52 @@ static int vpu_mem_over = 0; */ static void dump_status(void) { - vdm_link *link, *tmp_link; - vdm_region *region, *tmp_region; - vdm_session *session, *tmp_session; - - printk("vpu mem status dump :\n\n"); - - // °´ index ´òÓ¡È«²¿ region - printk("region:\n"); - list_for_each_entry_safe(region, tmp_region, &vdm_index, index_list) { - printk(" idx %6d pfn %6d used %3d post %3d\n", - region->index, region->pfn, region->used, region->post); - } - printk("free :\n"); - list_for_each_entry_safe(link, tmp_link, &vdm_free, status_link) { - printk(" idx %6d pfn %6d used %3d post %3d\n", - link->index, link->pfn, link->link_used, link->link_post); - } - printk("used :\n"); - list_for_each_entry_safe(link, tmp_link, &vdm_used, status_link) { - printk(" idx %6d pfn %6d used %3d post %3d\n", - link->index, link->pfn, link->link_used, link->link_post); - } - printk("post :\n"); - list_for_each_entry_safe(link, tmp_link, &vdm_post, status_link) { - printk(" idx %6d pfn %6d used %3d post %3d\n", - link->index, link->pfn, link->link_used, link->link_post); - } + vdm_link *link, *tmp_link; + vdm_pool *pool, *tmp_pool; + vdm_region *region, *tmp_region; + vdm_session *session, *tmp_session; + + printk("vpu mem status dump :\n\n"); + + // °´ index ´òÓ¡È«²¿ region + printk("region:\n"); + list_for_each_entry_safe(region, tmp_region, &vdm_index, index_list) { + printk(" idx %6d pfn %6d used %3d post %3d\n", + region->index, region->pfn, region->used, region->post); + } + printk("free :\n"); + list_for_each_entry_safe(link, tmp_link, &vdm_free, status_link) { + printk(" idx %6d pfn %6d ref %3d\n", + link->index, link->pfn, link->ref.used); + } + printk("used :\n"); + list_for_each_entry_safe(link, tmp_link, &vdm_used, status_link) { + printk(" idx %6d pfn %6d used %3d\n", + link->index, link->pfn, link->ref.used); + } + printk("post :\n"); + list_for_each_entry_safe(link, tmp_link, &vdm_post, status_link) { + printk(" idx %6d pfn %6d post %3d\n", + link->index, link->pfn, link->ref.post); + } - // ´òÓ¡ vpu_mem_info ÖеÄÈ«²¿ session µÄ region Õ¼ÓÃÇé¿ö - list_for_each_entry_safe(session, tmp_session, &vdm_proc, list_session) { - printk("pid: %d\n", session->pid); + // ´òÓ¡ vpu_mem_info ÖеÄÈ«²¿ session µÄ region Õ¼ÓÃÇé¿ö + list_for_each_entry_safe(session, tmp_session, &vdm_proc, list_session) { + printk("pid: %d\n", session->pid); - list_for_each_entry_safe(link, tmp_link, &session->list_used, session_link) { - printk("used: idx %6d pfn %6d used %3d\n", - link->index, link->pfn, link->link_used); - } - list_for_each_entry_safe(link, tmp_link, &session->list_post, session_link) { - printk("post: idx %6d pfn %6d post %3d\n", - link->index, link->pfn, link->link_post); - } - } + list_for_each_entry_safe(pool, tmp_pool, &session->list_pool, session_link) { + printk("pool: pfn %6d target %3d current %2d\n", + pool->pfn, pool->count_current, pool->count_target); + } + list_for_each_entry_safe(link, tmp_link, &session->list_used, session_link) { + printk("used: idx %6d pfn %6d used %3d\n", + link->index, link->pfn, link->ref.used); + } + list_for_each_entry_safe(link, tmp_link, &session->list_post, session_link) { + printk("post: idx %6d pfn %6d post %3d\n", + link->index, link->pfn, link->ref.post); + } + } } /** @@ -192,7 +226,7 @@ static vdm_link *find_used_link(vdm_session *session, int index) list_for_each_entry_safe(pos, n, &session->list_used, session_link) { if (index == pos->index) { - DLOG("found index %d ptr %x\n", index, pos); + DLOG("found index %d ptr %p\n", index, pos); return pos; } } @@ -243,6 +277,36 @@ static vdm_link *find_free_link(int index) return NULL; } + +static vdm_pool *find_pool_by_pfn(vdm_session *session, unsigned int pfn) +{ + vdm_pool *pos, *n; + + list_for_each_entry_safe(pos, n, &session->list_pool, session_link) { + if (pfn == pos->pfn) { + return pos; + } + } + + return NULL; +} + +static void link_ref_inc(vdm_link *link) +{ + link->ref.count++; + if (link->ref_ptr) { + *link->ref_ptr += 1; + } +} + +static void link_ref_dec(vdm_link *link) +{ + link->ref.count--; + if (link->ref_ptr) { + *link->ref_ptr -= 1; + } +} + /** * insert a region into the index list for search * @@ -267,7 +331,7 @@ static int _insert_region_index(vdm_region *region) list_for_each_entry_safe(tmp, n, &vdm_index, index_list) { next = tmp->index; - DLOG("insert index %d pfn %d last %d next %d ptr %x\n", index, region->pfn, last, next, tmp); + DLOG("insert index %d pfn %d last %d next %d ptr %p\n", index, region->pfn, last, next, tmp); if ((last < index) && (index < next)) { DLOG("Done\n"); list_add_tail(®ion->index_list, &tmp->index_list); @@ -304,14 +368,14 @@ static void _insert_link_status_free(vdm_link *link) list_for_each_entry_safe(tmp, n, &vdm_free, status_link) { next = tmp->index; if ((last < index) && (index < next)) { - DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp); + DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp); list_add_tail(&link->status_link, &tmp->status_link); return ; } last = next; } list_add_tail(&link->status_link, &tmp->status_link); - DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp); + DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp); return ; } @@ -331,7 +395,7 @@ static void _insert_link_status_post(vdm_link *link) list_for_each_entry_safe(tmp, n, &vdm_post, status_link) { next = tmp->index; if ((last < index) && (index < next)) { - DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp); + DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp); list_add_tail(&link->status_link, &tmp->status_link); return ; } @@ -339,7 +403,7 @@ static void _insert_link_status_post(vdm_link *link) } list_add_tail(&link->status_link, &tmp->status_link); - DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp); + DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp); return ; } @@ -359,7 +423,7 @@ static void _insert_link_status_used(vdm_link *link) list_for_each_entry_safe(tmp, n, &vdm_used, status_link) { next = tmp->index; if ((last < index) && (index < next)) { - DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp); + DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp); list_add_tail(&link->status_link, &tmp->status_link); return ; } @@ -367,7 +431,7 @@ static void _insert_link_status_used(vdm_link *link) } list_add_tail(&link->status_link, &tmp->status_link); - DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp); + DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp); return ; } @@ -388,14 +452,14 @@ static void _insert_link_session_used(vdm_link *link, vdm_session *session) next = tmp->index; if ((last < index) && (index < next)) { list_add_tail(&link->session_link, &tmp->session_link); - DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp); + DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp); return ; } last = next; } list_add_tail(&link->session_link, &tmp->session_link); - DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp); + DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp); return ; } @@ -416,14 +480,14 @@ static void _insert_link_session_post(vdm_link *link, vdm_session *session) next = tmp->index; if ((last < index) && (index < next)) { list_add_tail(&link->session_link, &tmp->session_link); - DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp); + DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp); return ; } last = next; } list_add_tail(&link->session_link, &tmp->session_link); - DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp); + DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp); return ; } @@ -478,25 +542,50 @@ static void merge_free_region_and_link(vdm_region *region) static void put_free_link(vdm_link *link) { - list_del_init(&link->session_link); - list_del_init(&link->status_link); - _insert_link_status_free(link); + if (link->pool) { + vdm_pool *pool = link->pool; + link->pool = NULL; + list_del_init(&link->pool_link); + pool->count_current--; + pool->count_used--; + } + list_del_init(&link->session_link); + list_del_init(&link->status_link); + _insert_link_status_free(link); } static void put_used_link(vdm_link *link, vdm_session *session) { - list_del_init(&link->session_link); - list_del_init(&link->status_link); - _insert_link_status_used(link); - _insert_link_session_used(link, session); + list_del_init(&link->session_link); + list_del_init(&link->status_link); + _insert_link_status_used(link); + _insert_link_session_used(link, session); + if (NULL == link->pool) { + vdm_pool *pool = find_pool_by_pfn(session, link->pfn); + if (pool) { + link->pool = pool; + list_add_tail(&link->pool_link, &pool->list_used); + pool->count_used++; + pool->count_current++; + } + } } static void put_post_link(vdm_link *link, vdm_session *session) { - list_del_init(&link->session_link); - list_del_init(&link->status_link); - _insert_link_status_post(link); - _insert_link_session_post(link, session); + list_del_init(&link->session_link); + list_del_init(&link->status_link); + _insert_link_status_post(link); + _insert_link_session_post(link, session); + if (NULL == link->pool) { + vdm_pool *pool = find_pool_by_pfn(session, link->pfn); + if (pool) { + link->pool = pool; + list_add_tail(&link->pool_link, &pool->list_used); + pool->count_used++; + pool->count_current++; + } + } } /** @@ -533,13 +622,15 @@ static vdm_link *new_link_by_index(int index, int pfn) INIT_LIST_HEAD(®ion->index_list); - link->link_post = 0; - link->link_used = 0; + link->ref.count = 0; + link->ref_ptr = NULL; link->region = region; link->index = region->index; link->pfn = region->pfn; INIT_LIST_HEAD(&link->session_link); INIT_LIST_HEAD(&link->status_link); + INIT_LIST_HEAD(&link->pool_link); + link->pool = NULL; return link; } @@ -562,13 +653,15 @@ static vdm_link *new_link_by_region(vdm_region *region) return NULL; } - link->link_post = 0; - link->link_used = 0; + link->ref.count = 0; + link->ref_ptr = NULL; link->region = region; link->index = region->index; link->pfn = region->pfn; INIT_LIST_HEAD(&link->session_link); INIT_LIST_HEAD(&link->status_link); + INIT_LIST_HEAD(&link->pool_link); + link->pool = NULL; return link; } @@ -582,9 +675,21 @@ static vdm_link *new_link_by_region(vdm_region *region) */ static void link_del(vdm_link *link) { - list_del_init(&link->session_link); - list_del_init(&link->status_link); - kfree(link); + if (link->pool) { + vdm_pool *pool = link->pool; + link->pool = NULL; + list_del_init(&link->pool_link); + pool->count_current--; + pool->count_used--; + } + list_del_init(&link->session_link); + list_del_init(&link->status_link); + if (is_free_region(link->region) && NULL == find_free_link(link->index)) { + put_free_link(link); + merge_free_region_and_link(link->region); + } else { + kfree(link); + } } /** @@ -606,8 +711,9 @@ static vdm_link *get_used_link_from_free_link(vdm_link *link, vdm_session *sessi } if (pfn == link->pfn) { DLOG("pfn == link->pfn %d\n", pfn); - link->link_used = 1; + link->ref.used = 1; link->region->used = 1; + link->ref_ptr = &link->region->used; put_used_link(link, session); return link; } else { @@ -619,10 +725,11 @@ static vdm_link *get_used_link_from_free_link(vdm_link *link, vdm_session *sessi link->pfn -= pfn; link->region->index += pfn; link->region->pfn -= pfn; - used->link_used = 1; - used->region->used = 1; + used->ref.used = 1; + used->region->used = 1; + used->ref_ptr = &used->region->used; - DLOG("used: index %d pfn %d ptr %x\n", used->index, used->pfn, used->region); + DLOG("used: index %d pfn %d ptr %p\n", used->index, used->pfn, used->region); if (_insert_region_index(used->region)) { printk(KERN_ALERT "fail to insert allocated region index %d pfn %d\n", used->index, used->pfn); link_del(used); @@ -639,18 +746,6 @@ static vdm_link *get_used_link_from_free_link(vdm_link *link, vdm_session *sessi } } -static int vpu_mem_release(struct inode *, struct file *); -static int vpu_mem_mmap(struct file *, struct vm_area_struct *); -static int vpu_mem_open(struct inode *, struct file *); -static long vpu_mem_ioctl(struct file *, unsigned int, unsigned long); - -struct file_operations vpu_mem_fops = { - .open = vpu_mem_open, - .mmap = vpu_mem_mmap, - .unlocked_ioctl = vpu_mem_ioctl, - .release = vpu_mem_release, -}; - int is_vpu_mem_file(struct file *file) { if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode)) @@ -663,42 +758,42 @@ int is_vpu_mem_file(struct file *file) static long vpu_mem_allocate(struct file *file, unsigned int len) { - vdm_link *free, *n; + vdm_link *free, *n; unsigned int pfn = (len + VPU_MEM_MIN_ALLOC - 1)/VPU_MEM_MIN_ALLOC; - vdm_session *session = (vdm_session *)file->private_data; + vdm_session *session = (vdm_session *)file->private_data; - if (!is_vpu_mem_file(file)) { - printk(KERN_INFO "allocate vpu_mem session from invalid file\n"); - return -ENODEV; - } + if (!is_vpu_mem_file(file)) { + printk(KERN_INFO "allocate vpu_mem session from invalid file\n"); + return -ENODEV; + } - list_for_each_entry_safe(free, n, &vdm_free, status_link) { - /* find match free buffer use it first */ - vdm_link *used = get_used_link_from_free_link(free, session, pfn); - DLOG("search free buffer at index %d pfn %d for len %d\n", free->index, free->pfn, pfn); - if (NULL == used) { - continue; - } else { - DLOG("found buffer at index %d pfn %d for ptr %x\n", used->index, used->pfn, used); - return used->index; - } - } + list_for_each_entry_safe(free, n, &vdm_free, status_link) { + /* find match free buffer use it first */ + vdm_link *used = get_used_link_from_free_link(free, session, pfn); + DLOG("search free buffer at index %d pfn %d for len %d\n", free->index, free->pfn, pfn); + if (NULL == used) { + continue; + } else { + DLOG("found buffer at index %d pfn %d for ptr %p\n", used->index, used->pfn, used); + return used->index; + } + } if (!vpu_mem_over) { - printk(KERN_INFO "vpu_mem: no space left to allocate!\n"); - dump_status(); - vpu_mem_over = 1; - } - return -1; + printk(KERN_INFO "vpu_mem: no space left to allocate!\n"); + dump_status(); + vpu_mem_over = 1; + } + return -1; } static int vpu_mem_free(struct file *file, int index) { - vdm_session *session = (vdm_session *)file->private_data; + vdm_session *session = (vdm_session *)file->private_data; - if (!is_vpu_mem_file(file)) { - printk(KERN_INFO "free vpu_mem session from invalid file.\n"); - return -ENODEV; + if (!is_vpu_mem_file(file)) { + printk(KERN_INFO "free vpu_mem session from invalid file.\n"); + return -ENODEV; } DLOG("searching for index %d\n", index); @@ -708,100 +803,175 @@ static int vpu_mem_free(struct file *file, int index) DLOG("no link of index %d searched\n", index); return -1; } - link->link_used--; - link->region->used--; - if (0 == link->link_used) { - if (is_free_region(link->region)) { - put_free_link(link); - merge_free_region_and_link(link->region); - } else { - link_del(link); - } + link_ref_dec(link); + if (0 == link->ref.used) { + link_del(link); } } - return 0; + return 0; } static int vpu_mem_duplicate(struct file *file, int index) { - vdm_session *session = (vdm_session *)file->private_data; + vdm_session *session = (vdm_session *)file->private_data; /* caller should hold the write lock on vpu_mem_sem! */ - if (!is_vpu_mem_file(file)) { - printk(KERN_INFO "duplicate vpu_mem session from invalid file.\n"); - return -ENODEV; - } + if (!is_vpu_mem_file(file)) { + printk(KERN_INFO "duplicate vpu_mem session from invalid file.\n"); + return -ENODEV; + } DLOG("duplicate index %d\n", index); - { - vdm_link *post = find_post_link(index); - if (NULL == post) { - vdm_link *used = find_used_link(session, index); - if (NULL == used) { - printk(KERN_ERR "try to duplicate unknown index %d\n", index); - dump_status(); - return -1; - } - post = new_link_by_region(used->region); - post->link_post = 1; - post->region->post++; - put_post_link(post, session); - } else { - DLOG("duplicate posted index %d\n", index); - post->link_post++; - post->region->post++; - } - } + { + vdm_link *post = find_post_link(index); + if (NULL == post) { + vdm_link *used = find_used_link(session, index); + if (NULL == used) { + printk(KERN_ERR "try to duplicate unknown index %d\n", index); + dump_status(); + return -1; + } + post = new_link_by_region(used->region); + post->ref_ptr = &post->region->post; + link_ref_inc(post); + put_post_link(post, session); + } else { + DLOG("duplicate posted index %d\n", index); + link_ref_inc(post); + } + } return 0; } static int vpu_mem_link(struct file *file, int index) { - vdm_session *session = (vdm_session *)file->private_data; + vdm_session *session = (vdm_session *)file->private_data; if (!is_vpu_mem_file(file)) { - printk(KERN_INFO "link vpu_mem session from invalid file.\n"); - return -ENODEV; + printk(KERN_INFO "link vpu_mem session from invalid file.\n"); + return -ENODEV; } - DLOG("link index %d\n", index); - { - vdm_link *post = find_post_link(index); - if (NULL == post) { - printk(KERN_ERR "try to link unknown index %d\n", index); - dump_status(); - return -1; - } else { - vdm_link *used = find_used_link(session, index); - post->link_post--; - post->region->post--; - if (0 == post->link_post) { - if (NULL == used) { - post->link_used++; - post->region->used++; - put_used_link(post, session); - } else { - used->link_used++; - used->region->used++; - link_del(post); - } - } else { - if (NULL == used) { - used = new_link_by_region(post->region); - used->link_used++; - used->region->used++; - put_used_link(used, session); - } else { - used->link_used++; - used->region->used++; - } - } - } - } + DLOG("link index %d\n", index); + { + vdm_link *post = find_post_link(index); + if (NULL == post) { + printk(KERN_ERR "try to link unknown index %d\n", index); + dump_status(); + return -1; + } else { + vdm_link *used = find_used_link(session, index); + link_ref_dec(post); + + if (used) { + if (0 == post->ref.post) { + link_del(post); + post = NULL; + } + } else { + if (post->ref.post) { + used = new_link_by_region(post->region); + } else { + used = post; + post = NULL; + } + used->ref_ptr = &used->region->used; + put_used_link(used, session); + } + link_ref_inc(used); + } + } return 0; } +static int vpu_mem_pool_add(vdm_session *session, unsigned int pfn, unsigned int count) +{ + vdm_link *link, *n; + vdm_pool *pool = kmalloc(sizeof(vdm_pool), GFP_KERNEL); + DLOG("vpu_mem_pool_add %p pfn %d count %d\n", pool, pfn, count); + if (NULL == pool) { + printk(KERN_ALERT "vpu_mem: unable to allocate memory for vpu_mem pool."); + return -1; + } + INIT_LIST_HEAD(&pool->session_link); + INIT_LIST_HEAD(&pool->list_used); + pool->session = session; + pool->pfn = pfn; + pool->count_target = count; + pool->count_current = 0; + pool->count_used = 0; + + list_for_each_entry_safe(link, n, &session->list_used, session_link) { + if (pfn == link->pfn && NULL == link->pool) { + link->pool = pool; + list_add_tail(&link->pool_link, &pool->list_used); + pool->count_used++; + pool->count_current++; + } + } + + list_add_tail(&pool->session_link, &session->list_pool); + + return 0; +} + +static void vpu_mem_pool_del(vdm_pool *pool) +{ + vdm_link *link, *n; + DLOG("vpu_mem_pool_del %p\n", pool); + list_for_each_entry_safe(link, n, &pool->list_used, pool_link) { + link->pool = NULL; + list_del_init(&link->pool_link); + pool->count_current--; + pool->count_used--; + } + return ; +} + +static int vpu_mem_pool_set(struct file *file, unsigned int pfn, unsigned int count) +{ + int ret = 0; + vdm_session *session = (vdm_session *)file->private_data; + vdm_pool *pool = find_pool_by_pfn(session, pfn); + if (NULL == pool) { + // no pool build pool first + ret = vpu_mem_pool_add(session, pfn, count); + } else { + pool->count_target += count; + } + return ret; +} + +static int vpu_mem_pool_unset(struct file *file, unsigned int pfn, unsigned int count) +{ + int ret = 0; + vdm_session *session = (vdm_session *)file->private_data; + vdm_pool *pool = find_pool_by_pfn(session, pfn); + if (pool) { + pool->count_target -= count; + if (pool->count_target <= 0) { + vpu_mem_pool_del(pool); + pool->count_target = 0; + } + } + return ret; +} + +static int vpu_mem_pool_check(struct file *file, unsigned int pfn) +{ + int ret = 0; + vdm_session *session = (vdm_session *)file->private_data; + vdm_pool *pool = find_pool_by_pfn(session, pfn); + if (pool) { + if (pool->count_current > pool->count_target) { + ret = 1; + } + DLOG("vpu_mem_pool_check pfn %u current %d target %d ret %d\n", pfn, pool->count_current, pool->count_target, ret); + } + return ret; +} + void vpu_mem_cache_opt(struct file *file, long index, unsigned int cmd) { vdm_session *session = (vdm_session *)file->private_data; @@ -815,32 +985,32 @@ void vpu_mem_cache_opt(struct file *file, long index, unsigned int cmd) return; down_read(&vdm_rwsem); - do { - vdm_link *link = find_used_link(session, index); - if (NULL == link) { - pr_err("vpu_mem_cache_opt on non-exsist index %ld\n", index); - break; - } - start = vpu_mem.vbase + index * VPU_MEM_MIN_ALLOC; - end = start + link->pfn * VPU_MEM_MIN_ALLOC;; - switch (cmd) { - case VPU_MEM_CACHE_FLUSH : { - dmac_flush_range(start, end); - break; - } - case VPU_MEM_CACHE_CLEAN : { - dmac_clean_range(start, end); - break; - } - case VPU_MEM_CACHE_INVALID : { - dmac_inv_range(start, end); - break; - } - default : - break; - } - } while (0); - up_read(&vdm_rwsem); + do { + vdm_link *link = find_used_link(session, index); + if (NULL == link) { + pr_err("vpu_mem_cache_opt on non-exsist index %ld\n", index); + break; + } + start = vpu_mem.vbase + index * VPU_MEM_MIN_ALLOC; + end = start + link->pfn * VPU_MEM_MIN_ALLOC;; + switch (cmd) { + case VPU_MEM_CACHE_FLUSH : { + dmac_flush_range(start, end); + break; + } + case VPU_MEM_CACHE_CLEAN : { + dmac_clean_range(start, end); + break; + } + case VPU_MEM_CACHE_INVALID : { + dmac_inv_range(start, end); + break; + } + default : + break; + } + } while (0); + up_read(&vdm_rwsem); } static pgprot_t vpu_mem_phys_mem_access_prot(struct file *file, pgprot_t vma_prot) @@ -888,6 +1058,7 @@ static int vpu_mem_open(struct inode *inode, struct file *file) session->pid = current->pid; INIT_LIST_HEAD(&session->list_post); INIT_LIST_HEAD(&session->list_used); + INIT_LIST_HEAD(&session->list_pool); file->private_data = session; @@ -899,7 +1070,7 @@ static int vpu_mem_open(struct inode *inode, struct file *file) static int vpu_mem_mmap(struct file *file, struct vm_area_struct *vma) { - vdm_session *session; + vdm_session *session; unsigned long vma_size = vma->vm_end - vma->vm_start; int ret = 0; @@ -911,7 +1082,7 @@ static int vpu_mem_mmap(struct file *file, struct vm_area_struct *vma) session = (vdm_session *)file->private_data; - /* assert: vma_size must be the total size of the vpu_mem */ + /* assert: vma_size must be the total size of the vpu_mem */ if (vpu_mem.size != vma_size) { printk(KERN_WARNING "vpu_mem: mmap size [%lu] does not match" "size of backing region [%lu].\n", vma_size, vpu_mem.size); @@ -948,31 +1119,15 @@ static int vpu_mem_release(struct inode *inode, struct file *file) list_for_each_entry_safe(link, tmp_link, &session->list_post, session_link) { do { - link->link_post--; - link->region->post--; - } while (link->link_post); - if (find_free_link(link->index)) { - link_del(link); - } else { - put_free_link(link); - } - if (is_free_region(link->region)) { - merge_free_region_and_link(link->region); - } + link_ref_dec(link); + } while (link->ref.post); + link_del(link); } list_for_each_entry_safe(link, tmp_link, &session->list_used, session_link) { do { - link->link_used--; - link->region->used--; - } while (link->link_used); - if (find_free_link(link->index)) { - link_del(link); - } else { - put_free_link(link); - } - if (is_free_region(link->region)) { - merge_free_region_and_link(link->region); - } + link_ref_dec(link); + } while (link->ref.used); + link_del(link); } } up_write(&vdm_rwsem); @@ -983,83 +1138,116 @@ static int vpu_mem_release(struct inode *inode, struct file *file) static long vpu_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - long index, ret = 0; + long index, ret = 0; switch (cmd) { - case VPU_MEM_GET_PHYS: + case VPU_MEM_GET_PHYS: { DLOG("get_phys\n"); printk(KERN_INFO "vpu_mem: request for physical address of vpu_mem region " "from process %d.\n", current->pid); if (copy_to_user((void __user *)arg, &vpu_mem.base, sizeof(vpu_mem.base))) - return -EFAULT; - break; - case VPU_MEM_GET_TOTAL_SIZE: + return -EFAULT; + } break; + case VPU_MEM_GET_TOTAL_SIZE: { DLOG("get total size\n"); if (copy_to_user((void __user *)arg, &vpu_mem.size, sizeof(vpu_mem.size))) return -EFAULT; - break; - case VPU_MEM_ALLOCATE: + } break; + case VPU_MEM_ALLOCATE: { + unsigned int size; DLOG("allocate\n"); - { - unsigned int size; - if (copy_from_user(&size, (void __user *)arg, sizeof(size))) - return -EFAULT; - down_write(&vdm_rwsem); - ret = vpu_mem_allocate(file, size); - up_write(&vdm_rwsem); - DLOG("allocate at index %ld\n", ret); - break; - } - case VPU_MEM_FREE: - DLOG("mem free\n"); - { - if (copy_from_user(&index, (void __user *)arg, sizeof(index))) - return -EFAULT; - if (index >= vpu_mem.size) - return -EACCES; - down_write(&vdm_rwsem); - ret = vpu_mem_free(file, index); - up_write(&vdm_rwsem); - break; - } + if (copy_from_user(&size, (void __user *)arg, sizeof(size))) + return -EFAULT; + down_write(&vdm_rwsem); + ret = vpu_mem_allocate(file, size); + up_write(&vdm_rwsem); + DLOG("allocate at index %ld\n", ret); + } break; + case VPU_MEM_FREE: { + DLOG("mem free\n"); + if (copy_from_user(&index, (void __user *)arg, sizeof(index))) + return -EFAULT; + if (index >= vpu_mem.size) + return -EACCES; + down_write(&vdm_rwsem); + ret = vpu_mem_free(file, index); + up_write(&vdm_rwsem); + } break; + case VPU_MEM_CACHE_FLUSH: - case VPU_MEM_CACHE_CLEAN: - case VPU_MEM_CACHE_INVALID: - DLOG("flush\n"); - { - if (copy_from_user(&index, (void __user *)arg, sizeof(index))) - return -EFAULT; - if (index < 0) - return -EINVAL; - vpu_mem_cache_opt(file, index, cmd); - break; - } - case VPU_MEM_DUPLICATE: - DLOG("duplicate\n"); - { - if (copy_from_user(&index, (void __user *)arg, sizeof(index))) - return -EFAULT; - down_write(&vdm_rwsem); - ret = vpu_mem_duplicate(file, index); - up_write(&vdm_rwsem); - break; - } - case VPU_MEM_LINK: - DLOG("link\n"); - { - if (copy_from_user(&index, (void __user *)arg, sizeof(index))) - return -EFAULT; - down_write(&vdm_rwsem); - ret = vpu_mem_link(file, index); - up_write(&vdm_rwsem); - break; - } + case VPU_MEM_CACHE_CLEAN: + case VPU_MEM_CACHE_INVALID: { + DLOG("flush\n"); + if (copy_from_user(&index, (void __user *)arg, sizeof(index))) + return -EFAULT; + if (index < 0) + return -EINVAL; + vpu_mem_cache_opt(file, index, cmd); + } break; + case VPU_MEM_DUPLICATE: { + DLOG("duplicate\n"); + if (copy_from_user(&index, (void __user *)arg, sizeof(index))) + return -EFAULT; + down_write(&vdm_rwsem); + ret = vpu_mem_duplicate(file, index); + up_write(&vdm_rwsem); + } break; + + case VPU_MEM_LINK: { + DLOG("link\n"); + if (copy_from_user(&index, (void __user *)arg, sizeof(index))) + return -EFAULT; + down_write(&vdm_rwsem); + ret = vpu_mem_link(file, index); + up_write(&vdm_rwsem); + } break; + + case VPU_MEM_POOL_SET: { + struct vpu_mem_pool_config config; + DLOG("pool set\n"); + if (copy_from_user(&config, (void __user *)arg, sizeof(config))) + return -EFAULT; + config.size = (config.size + VPU_MEM_MIN_ALLOC - 1)/VPU_MEM_MIN_ALLOC; + down_write(&vdm_rwsem); + ret = vpu_mem_pool_set(file, config.size, config.count); + up_write(&vdm_rwsem); + } break; + + case VPU_MEM_POOL_UNSET: { + struct vpu_mem_pool_config config; + DLOG("pool unset\n"); + if (copy_from_user(&config, (void __user *)arg, sizeof(config))) + return -EFAULT; + config.size = (config.size + VPU_MEM_MIN_ALLOC - 1)/VPU_MEM_MIN_ALLOC; + down_write(&vdm_rwsem); + ret = vpu_mem_pool_unset(file, config.size, config.count); + up_write(&vdm_rwsem); + } break; + + case VPU_MEM_POOL_CHECK: { + int pfn; + if (copy_from_user(&pfn, (void __user *)arg, sizeof(int))) + return -EFAULT; + pfn = (pfn + VPU_MEM_MIN_ALLOC - 1)/VPU_MEM_MIN_ALLOC; + DLOG("pool check\n"); + down_write(&vdm_rwsem); + ret = vpu_mem_pool_check(file, pfn); + up_write(&vdm_rwsem); + } break; + default: return -EINVAL; } return ret; } +struct file_operations vpu_mem_fops = { + .open = vpu_mem_open, + .mmap = vpu_mem_mmap, + .unlocked_ioctl = vpu_mem_ioctl, + .release = vpu_mem_release, +}; + #if VPU_MEM_DEBUG static ssize_t debug_open(struct inode *inode, struct file *file) { @@ -1230,6 +1418,7 @@ static int proc_vpu_mem_show(struct seq_file *s, void *v) down_read(&vdm_rwsem); { vdm_link *link, *tmp_link; + vdm_pool *pool, *tmp_pool; vdm_region *region, *tmp_region; vdm_session *session, *tmp_session; // °´ index ´òÓ¡È«²¿ region @@ -1244,7 +1433,7 @@ static int proc_vpu_mem_show(struct seq_file *s, void *v) seq_printf(s, "free :\n"); list_for_each_entry_safe(link, tmp_link, &vdm_free, status_link) { seq_printf(s, " idx %6d pfn %6d used %3d post %3d\n", - link->index, link->pfn, link->link_used, link->link_post); + link->index, link->pfn, link->ref.used, link->ref.post); } } if (list_empty(&vdm_used)) { @@ -1253,7 +1442,7 @@ static int proc_vpu_mem_show(struct seq_file *s, void *v) seq_printf(s, "used :\n"); list_for_each_entry_safe(link, tmp_link, &vdm_used, status_link) { seq_printf(s, " idx %6d pfn %6d used %3d post %3d\n", - link->index, link->pfn, link->link_used, link->link_post); + link->index, link->pfn, link->ref.used, link->ref.post); } } if (list_empty(&vdm_post)) { @@ -1262,20 +1451,29 @@ static int proc_vpu_mem_show(struct seq_file *s, void *v) seq_printf(s, "post :\n"); list_for_each_entry_safe(link, tmp_link, &vdm_post, status_link) { seq_printf(s, " idx %6d pfn %6d used %3d post %3d\n", - link->index, link->pfn, link->link_used, link->link_post); + link->index, link->pfn, link->ref.used, link->ref.post); } } // ´òÓ¡ vpu_mem_info ÖеÄÈ«²¿ session µÄ region Õ¼ÓÃÇé¿ö list_for_each_entry_safe(session, tmp_session, &vdm_proc, list_session) { seq_printf(s, "\npid: %d\n", session->pid); + if (list_empty(&session->list_pool)) { + seq_printf(s, "pool : empty\n"); + } else { + seq_printf(s, "pool :\n"); + list_for_each_entry_safe(pool, tmp_pool, &session->list_pool, session_link) { + seq_printf(s, " pfn %6d target %4d current %2d\n", + pool->pfn, pool->count_target, pool->count_current); + } + } if (list_empty(&session->list_used)) { seq_printf(s, "used : empty\n"); } else { seq_printf(s, "used :\n"); list_for_each_entry_safe(link, tmp_link, &session->list_used, session_link) { seq_printf(s, " idx %6d pfn %6d used %3d\n", - link->index, link->pfn, link->link_used); + link->index, link->pfn, link->ref.used); } } if (list_empty(&session->list_post)) { @@ -1284,7 +1482,7 @@ static int proc_vpu_mem_show(struct seq_file *s, void *v) seq_printf(s, "post :\n"); list_for_each_entry_safe(link, tmp_link, &session->list_post, session_link) { seq_printf(s, " idx %6d pfn %6d post %3d\n", - link->index, link->pfn, link->link_post); + link->index, link->pfn, link->ref.post); } } } -- 2.34.1