* @author ChenHengming (2011-4-11)\r
*/\r
typedef struct vpu_mem_session {\r
- /* a list of memory region used posted by current process */\r
- struct list_head list_used;\r
- struct list_head list_post;\r
- /* a linked list of data so we can access them for debugging */\r
- struct list_head list_session;\r
+ /* a list of memory region used posted by current process */\r
+ struct list_head list_used;\r
+ struct list_head list_post;\r
+ /* a linked list of data so we can access them for debugging */\r
+ struct list_head list_session;\r
+ /* a linked list of memory pool on current session */\r
+ struct list_head list_pool;\r
/* process id of teh mapping process */\r
pid_t pid;\r
} vdm_session;\r
\r
+/**\r
+ * session memory pool info\r
+ */\r
+typedef struct vpu_mem_pool_info {\r
+ struct list_head session_link; /* link to session use for search */\r
+ struct list_head list_used; /* a linked list for used memory in the pool */\r
+ vdm_session *session;\r
+ int count_current;\r
+ int count_target;\r
+ int count_used;\r
+ int pfn;\r
+} vdm_pool;\r
+\r
+/**\r
+ * session memory pool config input\r
+ */\r
+typedef struct vpu_mem_pool_config {\r
+ int size;\r
+ unsigned int count;\r
+} vdm_pool_config;\r
+\r
/**\r
* global region info\r
*/\r
typedef struct vpu_mem_region_info {\r
- struct list_head index_list; /* link to index list use for search */\r
- int used;\r
- int post;\r
- int index;\r
- int pfn;\r
+ struct list_head index_list; /* link to index list use for search */\r
+ int used;\r
+ int post;\r
+ int index;\r
+ int pfn;\r
} vdm_region;\r
\r
/**\r
* this struct should be modified with bitmap lock\r
*/\r
typedef struct vpu_mem_link_info {\r
- struct list_head session_link; /* link to vpu_mem_session list */\r
- struct list_head status_link; /* link to vdm_info.status list use for search */\r
- vdm_region *region;\r
- int link_post;\r
- int link_used;\r
- int index;\r
- int pfn;\r
+ struct list_head session_link; /* link to vpu_mem_session list */\r
+ struct list_head status_link; /* link to vdm_info.status list use for search */\r
+ struct list_head pool_link; /* link to vpu_mem_session pool list for search */\r
+ vdm_region *region;\r
+ vdm_pool *pool;\r
+ union {\r
+ int post;\r
+ int used;\r
+ int count;\r
+ } ref;\r
+ int *ref_ptr;\r
+ int index;\r
+ int pfn;\r
} vdm_link;\r
\r
/**\r
/*\r
* vdm_session init only store the free region but use a vdm_session for convenience\r
*/\r
- vdm_session status;\r
+ vdm_session status;\r
struct list_head list_index; /* sort by index */\r
- struct list_head list_free; /* free region list */\r
- struct list_head list_session; /* session list */\r
- struct rw_semaphore rw_sem;\r
+ struct list_head list_free; /* free region list */\r
+ struct list_head list_session; /* session list */\r
+ struct rw_semaphore rw_sem;\r
} vdm_info;\r
\r
static vdm_info vpu_mem;\r
*/\r
static void dump_status(void)\r
{\r
- vdm_link *link, *tmp_link;\r
- vdm_region *region, *tmp_region;\r
- vdm_session *session, *tmp_session;\r
-\r
- printk("vpu mem status dump :\n\n");\r
-\r
- // °´ index ´òÓ¡È«²¿ region\r
- printk("region:\n");\r
- list_for_each_entry_safe(region, tmp_region, &vdm_index, index_list) {\r
- printk(" idx %6d pfn %6d used %3d post %3d\n",\r
- region->index, region->pfn, region->used, region->post);\r
- }\r
- printk("free :\n");\r
- list_for_each_entry_safe(link, tmp_link, &vdm_free, status_link) {\r
- printk(" idx %6d pfn %6d used %3d post %3d\n",\r
- link->index, link->pfn, link->link_used, link->link_post);\r
- }\r
- printk("used :\n");\r
- list_for_each_entry_safe(link, tmp_link, &vdm_used, status_link) {\r
- printk(" idx %6d pfn %6d used %3d post %3d\n",\r
- link->index, link->pfn, link->link_used, link->link_post);\r
- }\r
- printk("post :\n");\r
- list_for_each_entry_safe(link, tmp_link, &vdm_post, status_link) {\r
- printk(" idx %6d pfn %6d used %3d post %3d\n",\r
- link->index, link->pfn, link->link_used, link->link_post);\r
- }\r
+ vdm_link *link, *tmp_link;\r
+ vdm_pool *pool, *tmp_pool;\r
+ vdm_region *region, *tmp_region;\r
+ vdm_session *session, *tmp_session;\r
+\r
+ printk("vpu mem status dump :\n\n");\r
+\r
+ // °´ index ´òÓ¡È«²¿ region\r
+ printk("region:\n");\r
+ list_for_each_entry_safe(region, tmp_region, &vdm_index, index_list) {\r
+ printk(" idx %6d pfn %6d used %3d post %3d\n",\r
+ region->index, region->pfn, region->used, region->post);\r
+ }\r
+ printk("free :\n");\r
+ list_for_each_entry_safe(link, tmp_link, &vdm_free, status_link) {\r
+ printk(" idx %6d pfn %6d ref %3d\n",\r
+ link->index, link->pfn, link->ref.used);\r
+ }\r
+ printk("used :\n");\r
+ list_for_each_entry_safe(link, tmp_link, &vdm_used, status_link) {\r
+ printk(" idx %6d pfn %6d used %3d\n",\r
+ link->index, link->pfn, link->ref.used);\r
+ }\r
+ printk("post :\n");\r
+ list_for_each_entry_safe(link, tmp_link, &vdm_post, status_link) {\r
+ printk(" idx %6d pfn %6d post %3d\n",\r
+ link->index, link->pfn, link->ref.post);\r
+ }\r
\r
- // ´òÓ¡ vpu_mem_info ÖеÄÈ«²¿ session µÄ region Õ¼ÓÃÇé¿ö\r
- list_for_each_entry_safe(session, tmp_session, &vdm_proc, list_session) {\r
- printk("pid: %d\n", session->pid);\r
+ // ´òÓ¡ vpu_mem_info ÖеÄÈ«²¿ session µÄ region Õ¼ÓÃÇé¿ö\r
+ list_for_each_entry_safe(session, tmp_session, &vdm_proc, list_session) {\r
+ printk("pid: %d\n", session->pid);\r
\r
- list_for_each_entry_safe(link, tmp_link, &session->list_used, session_link) {\r
- printk("used: idx %6d pfn %6d used %3d\n",\r
- link->index, link->pfn, link->link_used);\r
- }\r
- list_for_each_entry_safe(link, tmp_link, &session->list_post, session_link) {\r
- printk("post: idx %6d pfn %6d post %3d\n",\r
- link->index, link->pfn, link->link_post);\r
- }\r
- }\r
+ list_for_each_entry_safe(pool, tmp_pool, &session->list_pool, session_link) {\r
+ printk("pool: pfn %6d target %3d current %2d\n",\r
+ pool->pfn, pool->count_current, pool->count_target);\r
+ }\r
+ list_for_each_entry_safe(link, tmp_link, &session->list_used, session_link) {\r
+ printk("used: idx %6d pfn %6d used %3d\n",\r
+ link->index, link->pfn, link->ref.used);\r
+ }\r
+ list_for_each_entry_safe(link, tmp_link, &session->list_post, session_link) {\r
+ printk("post: idx %6d pfn %6d post %3d\n",\r
+ link->index, link->pfn, link->ref.post);\r
+ }\r
+ }\r
}\r
\r
/**\r
\r
list_for_each_entry_safe(pos, n, &session->list_used, session_link) {\r
if (index == pos->index) {\r
- DLOG("found index %d ptr %x\n", index, pos);\r
+ DLOG("found index %d ptr %p\n", index, pos);\r
return pos;\r
}\r
}\r
\r
return NULL;\r
}\r
+\r
+static vdm_pool *find_pool_by_pfn(vdm_session *session, unsigned int pfn)\r
+{\r
+ vdm_pool *pos, *n;\r
+\r
+ list_for_each_entry_safe(pos, n, &session->list_pool, session_link) {\r
+ if (pfn == pos->pfn) {\r
+ return pos;\r
+ }\r
+ }\r
+\r
+ return NULL;\r
+}\r
+\r
+static void link_ref_inc(vdm_link *link)\r
+{\r
+ link->ref.count++;\r
+ if (link->ref_ptr) {\r
+ *link->ref_ptr += 1;\r
+ }\r
+}\r
+\r
+static void link_ref_dec(vdm_link *link)\r
+{\r
+ link->ref.count--;\r
+ if (link->ref_ptr) {\r
+ *link->ref_ptr -= 1;\r
+ }\r
+}\r
+\r
/**\r
* insert a region into the index list for search\r
*\r
\r
list_for_each_entry_safe(tmp, n, &vdm_index, index_list) {\r
next = tmp->index;\r
- DLOG("insert index %d pfn %d last %d next %d ptr %x\n", index, region->pfn, last, next, tmp);\r
+ DLOG("insert index %d pfn %d last %d next %d ptr %p\n", index, region->pfn, last, next, tmp);\r
if ((last < index) && (index < next)) {\r
DLOG("Done\n");\r
list_add_tail(®ion->index_list, &tmp->index_list);\r
list_for_each_entry_safe(tmp, n, &vdm_free, status_link) {\r
next = tmp->index;\r
if ((last < index) && (index < next)) {\r
- DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp);\r
+ DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp);\r
list_add_tail(&link->status_link, &tmp->status_link);\r
return ;\r
}\r
last = next;\r
}\r
list_add_tail(&link->status_link, &tmp->status_link);\r
- DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp);\r
+ DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp);\r
return ;\r
}\r
\r
list_for_each_entry_safe(tmp, n, &vdm_post, status_link) {\r
next = tmp->index;\r
if ((last < index) && (index < next)) {\r
- DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp);\r
+ DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp);\r
list_add_tail(&link->status_link, &tmp->status_link);\r
return ;\r
}\r
}\r
\r
list_add_tail(&link->status_link, &tmp->status_link);\r
- DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp);\r
+ DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp);\r
return ;\r
}\r
\r
list_for_each_entry_safe(tmp, n, &vdm_used, status_link) {\r
next = tmp->index;\r
if ((last < index) && (index < next)) {\r
- DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp);\r
+ DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp);\r
list_add_tail(&link->status_link, &tmp->status_link);\r
return ;\r
}\r
}\r
\r
list_add_tail(&link->status_link, &tmp->status_link);\r
- DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp);\r
+ DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp);\r
return ;\r
}\r
\r
next = tmp->index;\r
if ((last < index) && (index < next)) {\r
list_add_tail(&link->session_link, &tmp->session_link);\r
- DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp);\r
+ DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp);\r
return ;\r
}\r
last = next;\r
}\r
\r
list_add_tail(&link->session_link, &tmp->session_link);\r
- DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp);\r
+ DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp);\r
return ;\r
}\r
\r
next = tmp->index;\r
if ((last < index) && (index < next)) {\r
list_add_tail(&link->session_link, &tmp->session_link);\r
- DLOG("list_add_tail index %d pfn %d last %d next %d ptr %x\n", index, link->pfn, last, next, tmp);\r
+ DLOG("list_add_tail index %d pfn %d last %d next %d ptr %p\n", index, link->pfn, last, next, tmp);\r
return ;\r
}\r
last = next;\r
}\r
\r
list_add_tail(&link->session_link, &tmp->session_link);\r
- DLOG("list_add index %d pfn %d last %d ptr %x\n", index, link->pfn, last, tmp);\r
+ DLOG("list_add index %d pfn %d last %d ptr %p\n", index, link->pfn, last, tmp);\r
return ;\r
}\r
\r
\r
static void put_free_link(vdm_link *link)\r
{\r
- list_del_init(&link->session_link);\r
- list_del_init(&link->status_link);\r
- _insert_link_status_free(link);\r
+ if (link->pool) {\r
+ vdm_pool *pool = link->pool;\r
+ link->pool = NULL;\r
+ list_del_init(&link->pool_link);\r
+ pool->count_current--;\r
+ pool->count_used--;\r
+ }\r
+ list_del_init(&link->session_link);\r
+ list_del_init(&link->status_link);\r
+ _insert_link_status_free(link);\r
}\r
\r
static void put_used_link(vdm_link *link, vdm_session *session)\r
{\r
- list_del_init(&link->session_link);\r
- list_del_init(&link->status_link);\r
- _insert_link_status_used(link);\r
- _insert_link_session_used(link, session);\r
+ list_del_init(&link->session_link);\r
+ list_del_init(&link->status_link);\r
+ _insert_link_status_used(link);\r
+ _insert_link_session_used(link, session);\r
+ if (NULL == link->pool) {\r
+ vdm_pool *pool = find_pool_by_pfn(session, link->pfn);\r
+ if (pool) {\r
+ link->pool = pool;\r
+ list_add_tail(&link->pool_link, &pool->list_used);\r
+ pool->count_used++;\r
+ pool->count_current++;\r
+ }\r
+ }\r
}\r
\r
static void put_post_link(vdm_link *link, vdm_session *session)\r
{\r
- list_del_init(&link->session_link);\r
- list_del_init(&link->status_link);\r
- _insert_link_status_post(link);\r
- _insert_link_session_post(link, session);\r
+ list_del_init(&link->session_link);\r
+ list_del_init(&link->status_link);\r
+ _insert_link_status_post(link);\r
+ _insert_link_session_post(link, session);\r
+ if (NULL == link->pool) {\r
+ vdm_pool *pool = find_pool_by_pfn(session, link->pfn);\r
+ if (pool) {\r
+ link->pool = pool;\r
+ list_add_tail(&link->pool_link, &pool->list_used);\r
+ pool->count_used++;\r
+ pool->count_current++;\r
+ }\r
+ }\r
}\r
\r
/**\r
\r
INIT_LIST_HEAD(®ion->index_list);\r
\r
- link->link_post = 0;\r
- link->link_used = 0;\r
+ link->ref.count = 0;\r
+ link->ref_ptr = NULL;\r
link->region = region;\r
link->index = region->index;\r
link->pfn = region->pfn;\r
INIT_LIST_HEAD(&link->session_link);\r
INIT_LIST_HEAD(&link->status_link);\r
+ INIT_LIST_HEAD(&link->pool_link);\r
+ link->pool = NULL;\r
\r
return link;\r
}\r
return NULL;\r
}\r
\r
- link->link_post = 0;\r
- link->link_used = 0;\r
+ link->ref.count = 0;\r
+ link->ref_ptr = NULL;\r
link->region = region;\r
link->index = region->index;\r
link->pfn = region->pfn;\r
INIT_LIST_HEAD(&link->session_link);\r
INIT_LIST_HEAD(&link->status_link);\r
+ INIT_LIST_HEAD(&link->pool_link);\r
+ link->pool = NULL;\r
\r
return link;\r
}\r
*/\r
static void link_del(vdm_link *link)\r
{\r
- list_del_init(&link->session_link);\r
- list_del_init(&link->status_link);\r
- kfree(link);\r
+ if (link->pool) {\r
+ vdm_pool *pool = link->pool;\r
+ link->pool = NULL;\r
+ list_del_init(&link->pool_link);\r
+ pool->count_current--;\r
+ pool->count_used--;\r
+ }\r
+ list_del_init(&link->session_link);\r
+ list_del_init(&link->status_link);\r
+ if (is_free_region(link->region) && NULL == find_free_link(link->index)) {\r
+ put_free_link(link);\r
+ merge_free_region_and_link(link->region);\r
+ } else {\r
+ kfree(link);\r
+ }\r
}\r
\r
/**\r
}\r
if (pfn == link->pfn) {\r
DLOG("pfn == link->pfn %d\n", pfn);\r
- link->link_used = 1;\r
+ link->ref.used = 1;\r
link->region->used = 1;\r
+ link->ref_ptr = &link->region->used;\r
put_used_link(link, session);\r
return link;\r
} else {\r
link->pfn -= pfn;\r
link->region->index += pfn;\r
link->region->pfn -= pfn;\r
- used->link_used = 1;\r
- used->region->used = 1;\r
+ used->ref.used = 1;\r
+ used->region->used = 1;\r
+ used->ref_ptr = &used->region->used;\r
\r
- DLOG("used: index %d pfn %d ptr %x\n", used->index, used->pfn, used->region);\r
+ DLOG("used: index %d pfn %d ptr %p\n", used->index, used->pfn, used->region);\r
if (_insert_region_index(used->region)) {\r
printk(KERN_ALERT "fail to insert allocated region index %d pfn %d\n", used->index, used->pfn);\r
link_del(used);\r
}\r
}\r
\r
-static int vpu_mem_release(struct inode *, struct file *);\r
-static int vpu_mem_mmap(struct file *, struct vm_area_struct *);\r
-static int vpu_mem_open(struct inode *, struct file *);\r
-static long vpu_mem_ioctl(struct file *, unsigned int, unsigned long);\r
-\r
-struct file_operations vpu_mem_fops = {\r
- .open = vpu_mem_open,\r
- .mmap = vpu_mem_mmap,\r
- .unlocked_ioctl = vpu_mem_ioctl,\r
- .release = vpu_mem_release,\r
-};\r
-\r
int is_vpu_mem_file(struct file *file)\r
{\r
if (unlikely(!file || !file->f_dentry || !file->f_dentry->d_inode))\r
\r
static long vpu_mem_allocate(struct file *file, unsigned int len)\r
{\r
- vdm_link *free, *n;\r
+ vdm_link *free, *n;\r
unsigned int pfn = (len + VPU_MEM_MIN_ALLOC - 1)/VPU_MEM_MIN_ALLOC;\r
- vdm_session *session = (vdm_session *)file->private_data;\r
+ vdm_session *session = (vdm_session *)file->private_data;\r
\r
- if (!is_vpu_mem_file(file)) {\r
- printk(KERN_INFO "allocate vpu_mem session from invalid file\n");\r
- return -ENODEV;\r
- }\r
+ if (!is_vpu_mem_file(file)) {\r
+ printk(KERN_INFO "allocate vpu_mem session from invalid file\n");\r
+ return -ENODEV;\r
+ }\r
\r
- list_for_each_entry_safe(free, n, &vdm_free, status_link) {\r
- /* find match free buffer use it first */\r
- vdm_link *used = get_used_link_from_free_link(free, session, pfn);\r
- DLOG("search free buffer at index %d pfn %d for len %d\n", free->index, free->pfn, pfn);\r
- if (NULL == used) {\r
- continue;\r
- } else {\r
- DLOG("found buffer at index %d pfn %d for ptr %x\n", used->index, used->pfn, used);\r
- return used->index;\r
- }\r
- }\r
+ list_for_each_entry_safe(free, n, &vdm_free, status_link) {\r
+ /* find match free buffer use it first */\r
+ vdm_link *used = get_used_link_from_free_link(free, session, pfn);\r
+ DLOG("search free buffer at index %d pfn %d for len %d\n", free->index, free->pfn, pfn);\r
+ if (NULL == used) {\r
+ continue;\r
+ } else {\r
+ DLOG("found buffer at index %d pfn %d for ptr %p\n", used->index, used->pfn, used);\r
+ return used->index;\r
+ }\r
+ }\r
\r
if (!vpu_mem_over) {\r
- printk(KERN_INFO "vpu_mem: no space left to allocate!\n");\r
- dump_status();\r
- vpu_mem_over = 1;\r
- }\r
- return -1;\r
+ printk(KERN_INFO "vpu_mem: no space left to allocate!\n");\r
+ dump_status();\r
+ vpu_mem_over = 1;\r
+ }\r
+ return -1;\r
}\r
\r
static int vpu_mem_free(struct file *file, int index)\r
{\r
- vdm_session *session = (vdm_session *)file->private_data;\r
+ vdm_session *session = (vdm_session *)file->private_data;\r
\r
- if (!is_vpu_mem_file(file)) {\r
- printk(KERN_INFO "free vpu_mem session from invalid file.\n");\r
- return -ENODEV;\r
+ if (!is_vpu_mem_file(file)) {\r
+ printk(KERN_INFO "free vpu_mem session from invalid file.\n");\r
+ return -ENODEV;\r
}\r
\r
DLOG("searching for index %d\n", index);\r
DLOG("no link of index %d searched\n", index);\r
return -1;\r
}\r
- link->link_used--;\r
- link->region->used--;\r
- if (0 == link->link_used) {\r
- if (is_free_region(link->region)) {\r
- put_free_link(link);\r
- merge_free_region_and_link(link->region);\r
- } else {\r
- link_del(link);\r
- }\r
+ link_ref_dec(link);\r
+ if (0 == link->ref.used) {\r
+ link_del(link);\r
}\r
}\r
- return 0;\r
+ return 0;\r
}\r
\r
static int vpu_mem_duplicate(struct file *file, int index)\r
{\r
- vdm_session *session = (vdm_session *)file->private_data;\r
+ vdm_session *session = (vdm_session *)file->private_data;\r
/* caller should hold the write lock on vpu_mem_sem! */\r
- if (!is_vpu_mem_file(file)) {\r
- printk(KERN_INFO "duplicate vpu_mem session from invalid file.\n");\r
- return -ENODEV;\r
- }\r
+ if (!is_vpu_mem_file(file)) {\r
+ printk(KERN_INFO "duplicate vpu_mem session from invalid file.\n");\r
+ return -ENODEV;\r
+ }\r
\r
DLOG("duplicate index %d\n", index);\r
- {\r
- vdm_link *post = find_post_link(index);\r
- if (NULL == post) {\r
- vdm_link *used = find_used_link(session, index);\r
- if (NULL == used) {\r
- printk(KERN_ERR "try to duplicate unknown index %d\n", index);\r
- dump_status();\r
- return -1;\r
- }\r
- post = new_link_by_region(used->region);\r
- post->link_post = 1;\r
- post->region->post++;\r
- put_post_link(post, session);\r
- } else {\r
- DLOG("duplicate posted index %d\n", index);\r
- post->link_post++;\r
- post->region->post++;\r
- }\r
- }\r
+ {\r
+ vdm_link *post = find_post_link(index);\r
+ if (NULL == post) {\r
+ vdm_link *used = find_used_link(session, index);\r
+ if (NULL == used) {\r
+ printk(KERN_ERR "try to duplicate unknown index %d\n", index);\r
+ dump_status();\r
+ return -1;\r
+ }\r
+ post = new_link_by_region(used->region);\r
+ post->ref_ptr = &post->region->post;\r
+ link_ref_inc(post);\r
+ put_post_link(post, session);\r
+ } else {\r
+ DLOG("duplicate posted index %d\n", index);\r
+ link_ref_inc(post);\r
+ }\r
+ }\r
\r
return 0;\r
}\r
\r
static int vpu_mem_link(struct file *file, int index)\r
{\r
- vdm_session *session = (vdm_session *)file->private_data;\r
+ vdm_session *session = (vdm_session *)file->private_data;\r
\r
if (!is_vpu_mem_file(file)) {\r
- printk(KERN_INFO "link vpu_mem session from invalid file.\n");\r
- return -ENODEV;\r
+ printk(KERN_INFO "link vpu_mem session from invalid file.\n");\r
+ return -ENODEV;\r
}\r
\r
- DLOG("link index %d\n", index);\r
- {\r
- vdm_link *post = find_post_link(index);\r
- if (NULL == post) {\r
- printk(KERN_ERR "try to link unknown index %d\n", index);\r
- dump_status();\r
- return -1;\r
- } else {\r
- vdm_link *used = find_used_link(session, index);\r
- post->link_post--;\r
- post->region->post--;\r
- if (0 == post->link_post) {\r
- if (NULL == used) {\r
- post->link_used++;\r
- post->region->used++;\r
- put_used_link(post, session);\r
- } else {\r
- used->link_used++;\r
- used->region->used++;\r
- link_del(post);\r
- }\r
- } else {\r
- if (NULL == used) {\r
- used = new_link_by_region(post->region);\r
- used->link_used++;\r
- used->region->used++;\r
- put_used_link(used, session);\r
- } else {\r
- used->link_used++;\r
- used->region->used++;\r
- }\r
- }\r
- }\r
- }\r
+ DLOG("link index %d\n", index);\r
+ {\r
+ vdm_link *post = find_post_link(index);\r
+ if (NULL == post) {\r
+ printk(KERN_ERR "try to link unknown index %d\n", index);\r
+ dump_status();\r
+ return -1;\r
+ } else {\r
+ vdm_link *used = find_used_link(session, index);\r
+ link_ref_dec(post);\r
+\r
+ if (used) {\r
+ if (0 == post->ref.post) {\r
+ link_del(post);\r
+ post = NULL;\r
+ }\r
+ } else {\r
+ if (post->ref.post) {\r
+ used = new_link_by_region(post->region);\r
+ } else {\r
+ used = post;\r
+ post = NULL;\r
+ }\r
+ used->ref_ptr = &used->region->used;\r
+ put_used_link(used, session);\r
+ }\r
+ link_ref_inc(used);\r
+ }\r
+ }\r
\r
return 0;\r
}\r
\r
+static int vpu_mem_pool_add(vdm_session *session, unsigned int pfn, unsigned int count)\r
+{\r
+ vdm_link *link, *n;\r
+ vdm_pool *pool = kmalloc(sizeof(vdm_pool), GFP_KERNEL);\r
+ DLOG("vpu_mem_pool_add %p pfn %d count %d\n", pool, pfn, count);\r
+ if (NULL == pool) {\r
+ printk(KERN_ALERT "vpu_mem: unable to allocate memory for vpu_mem pool.");\r
+ return -1;\r
+ }\r
+ INIT_LIST_HEAD(&pool->session_link);\r
+ INIT_LIST_HEAD(&pool->list_used);\r
+ pool->session = session;\r
+ pool->pfn = pfn;\r
+ pool->count_target = count;\r
+ pool->count_current = 0;\r
+ pool->count_used = 0;\r
+\r
+ list_for_each_entry_safe(link, n, &session->list_used, session_link) {\r
+ if (pfn == link->pfn && NULL == link->pool) {\r
+ link->pool = pool;\r
+ list_add_tail(&link->pool_link, &pool->list_used);\r
+ pool->count_used++;\r
+ pool->count_current++;\r
+ }\r
+ }\r
+\r
+ list_add_tail(&pool->session_link, &session->list_pool);\r
+\r
+ return 0;\r
+}\r
+\r
+static void vpu_mem_pool_del(vdm_pool *pool)\r
+{\r
+ vdm_link *link, *n;\r
+ DLOG("vpu_mem_pool_del %p\n", pool);\r
+ list_for_each_entry_safe(link, n, &pool->list_used, pool_link) {\r
+ link->pool = NULL;\r
+ list_del_init(&link->pool_link);\r
+ pool->count_current--;\r
+ pool->count_used--;\r
+ }\r
+ return ;\r
+}\r
+\r
+static int vpu_mem_pool_set(struct file *file, unsigned int pfn, unsigned int count)\r
+{\r
+ int ret = 0;\r
+ vdm_session *session = (vdm_session *)file->private_data;\r
+ vdm_pool *pool = find_pool_by_pfn(session, pfn);\r
+ if (NULL == pool) {\r
+ // no pool build pool first\r
+ ret = vpu_mem_pool_add(session, pfn, count);\r
+ } else {\r
+ pool->count_target += count;\r
+ }\r
+ return ret;\r
+}\r
+\r
+static int vpu_mem_pool_unset(struct file *file, unsigned int pfn, unsigned int count)\r
+{\r
+ int ret = 0;\r
+ vdm_session *session = (vdm_session *)file->private_data;\r
+ vdm_pool *pool = find_pool_by_pfn(session, pfn);\r
+ if (pool) {\r
+ pool->count_target -= count;\r
+ if (pool->count_target <= 0) {\r
+ vpu_mem_pool_del(pool);\r
+ pool->count_target = 0;\r
+ }\r
+ }\r
+ return ret;\r
+}\r
+\r
+static int vpu_mem_pool_check(struct file *file, unsigned int pfn)\r
+{\r
+ int ret = 0;\r
+ vdm_session *session = (vdm_session *)file->private_data;\r
+ vdm_pool *pool = find_pool_by_pfn(session, pfn);\r
+ if (pool) {\r
+ if (pool->count_current > pool->count_target) {\r
+ ret = 1;\r
+ }\r
+ DLOG("vpu_mem_pool_check pfn %u current %d target %d ret %d\n", pfn, pool->count_current, pool->count_target, ret);\r
+ }\r
+ return ret;\r
+}\r
+\r
void vpu_mem_cache_opt(struct file *file, long index, unsigned int cmd)\r
{\r
vdm_session *session = (vdm_session *)file->private_data;\r
return;\r
\r
down_read(&vdm_rwsem);\r
- do {\r
- vdm_link *link = find_used_link(session, index);\r
- if (NULL == link) {\r
- pr_err("vpu_mem_cache_opt on non-exsist index %ld\n", index);\r
- break;\r
- }\r
- start = vpu_mem.vbase + index * VPU_MEM_MIN_ALLOC;\r
- end = start + link->pfn * VPU_MEM_MIN_ALLOC;;\r
- switch (cmd) {\r
- case VPU_MEM_CACHE_FLUSH : {\r
- dmac_flush_range(start, end);\r
- break;\r
- }\r
- case VPU_MEM_CACHE_CLEAN : {\r
- dmac_clean_range(start, end);\r
- break;\r
- }\r
- case VPU_MEM_CACHE_INVALID : {\r
- dmac_inv_range(start, end);\r
- break;\r
- }\r
- default :\r
- break;\r
- }\r
- } while (0);\r
- up_read(&vdm_rwsem);\r
+ do {\r
+ vdm_link *link = find_used_link(session, index);\r
+ if (NULL == link) {\r
+ pr_err("vpu_mem_cache_opt on non-exsist index %ld\n", index);\r
+ break;\r
+ }\r
+ start = vpu_mem.vbase + index * VPU_MEM_MIN_ALLOC;\r
+ end = start + link->pfn * VPU_MEM_MIN_ALLOC;;\r
+ switch (cmd) {\r
+ case VPU_MEM_CACHE_FLUSH : {\r
+ dmac_flush_range(start, end);\r
+ break;\r
+ }\r
+ case VPU_MEM_CACHE_CLEAN : {\r
+ dmac_clean_range(start, end);\r
+ break;\r
+ }\r
+ case VPU_MEM_CACHE_INVALID : {\r
+ dmac_inv_range(start, end);\r
+ break;\r
+ }\r
+ default :\r
+ break;\r
+ }\r
+ } while (0);\r
+ up_read(&vdm_rwsem);\r
}\r
\r
static pgprot_t vpu_mem_phys_mem_access_prot(struct file *file, pgprot_t vma_prot)\r
session->pid = current->pid;\r
INIT_LIST_HEAD(&session->list_post);\r
INIT_LIST_HEAD(&session->list_used);\r
+ INIT_LIST_HEAD(&session->list_pool);\r
\r
file->private_data = session;\r
\r
\r
static int vpu_mem_mmap(struct file *file, struct vm_area_struct *vma)\r
{\r
- vdm_session *session;\r
+ vdm_session *session;\r
unsigned long vma_size = vma->vm_end - vma->vm_start;\r
int ret = 0;\r
\r
\r
session = (vdm_session *)file->private_data;\r
\r
- /* assert: vma_size must be the total size of the vpu_mem */\r
+ /* assert: vma_size must be the total size of the vpu_mem */\r
if (vpu_mem.size != vma_size) {\r
printk(KERN_WARNING "vpu_mem: mmap size [%lu] does not match"\r
"size of backing region [%lu].\n", vma_size, vpu_mem.size);\r
\r
list_for_each_entry_safe(link, tmp_link, &session->list_post, session_link) {\r
do {\r
- link->link_post--;\r
- link->region->post--;\r
- } while (link->link_post);\r
- if (find_free_link(link->index)) {\r
- link_del(link);\r
- } else {\r
- put_free_link(link);\r
- }\r
- if (is_free_region(link->region)) {\r
- merge_free_region_and_link(link->region);\r
- }\r
+ link_ref_dec(link);\r
+ } while (link->ref.post);\r
+ link_del(link);\r
}\r
list_for_each_entry_safe(link, tmp_link, &session->list_used, session_link) {\r
do {\r
- link->link_used--;\r
- link->region->used--;\r
- } while (link->link_used);\r
- if (find_free_link(link->index)) {\r
- link_del(link);\r
- } else {\r
- put_free_link(link);\r
- }\r
- if (is_free_region(link->region)) {\r
- merge_free_region_and_link(link->region);\r
- }\r
+ link_ref_dec(link);\r
+ } while (link->ref.used);\r
+ link_del(link);\r
}\r
}\r
up_write(&vdm_rwsem);\r
\r
static long vpu_mem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
{\r
- long index, ret = 0;\r
+ long index, ret = 0;\r
\r
switch (cmd) {\r
- case VPU_MEM_GET_PHYS:\r
+ case VPU_MEM_GET_PHYS: {\r
DLOG("get_phys\n");\r
printk(KERN_INFO "vpu_mem: request for physical address of vpu_mem region "\r
"from process %d.\n", current->pid);\r
if (copy_to_user((void __user *)arg, &vpu_mem.base, sizeof(vpu_mem.base)))\r
- return -EFAULT;\r
- break;\r
- case VPU_MEM_GET_TOTAL_SIZE:\r
+ return -EFAULT;\r
+ } break;\r
+ case VPU_MEM_GET_TOTAL_SIZE: {\r
DLOG("get total size\n");\r
if (copy_to_user((void __user *)arg, &vpu_mem.size, sizeof(vpu_mem.size)))\r
return -EFAULT;\r
- break;\r
- case VPU_MEM_ALLOCATE:\r
+ } break;\r
+ case VPU_MEM_ALLOCATE: {\r
+ unsigned int size;\r
DLOG("allocate\n");\r
- {\r
- unsigned int size;\r
- if (copy_from_user(&size, (void __user *)arg, sizeof(size)))\r
- return -EFAULT;\r
- down_write(&vdm_rwsem);\r
- ret = vpu_mem_allocate(file, size);\r
- up_write(&vdm_rwsem);\r
- DLOG("allocate at index %ld\n", ret);\r
- break;\r
- }\r
- case VPU_MEM_FREE:\r
- DLOG("mem free\n");\r
- {\r
- if (copy_from_user(&index, (void __user *)arg, sizeof(index)))\r
- return -EFAULT;\r
- if (index >= vpu_mem.size)\r
- return -EACCES;\r
- down_write(&vdm_rwsem);\r
- ret = vpu_mem_free(file, index);\r
- up_write(&vdm_rwsem);\r
- break;\r
- }\r
+ if (copy_from_user(&size, (void __user *)arg, sizeof(size)))\r
+ return -EFAULT;\r
+ down_write(&vdm_rwsem);\r
+ ret = vpu_mem_allocate(file, size);\r
+ up_write(&vdm_rwsem);\r
+ DLOG("allocate at index %ld\n", ret);\r
+ } break;\r
+ case VPU_MEM_FREE: {\r
+ DLOG("mem free\n");\r
+ if (copy_from_user(&index, (void __user *)arg, sizeof(index)))\r
+ return -EFAULT;\r
+ if (index >= vpu_mem.size)\r
+ return -EACCES;\r
+ down_write(&vdm_rwsem);\r
+ ret = vpu_mem_free(file, index);\r
+ up_write(&vdm_rwsem);\r
+ } break;\r
+\r
case VPU_MEM_CACHE_FLUSH:\r
- case VPU_MEM_CACHE_CLEAN:\r
- case VPU_MEM_CACHE_INVALID:\r
- DLOG("flush\n");\r
- {\r
- if (copy_from_user(&index, (void __user *)arg, sizeof(index)))\r
- return -EFAULT;\r
- if (index < 0)\r
- return -EINVAL;\r
- vpu_mem_cache_opt(file, index, cmd);\r
- break;\r
- }\r
- case VPU_MEM_DUPLICATE:\r
- DLOG("duplicate\n");\r
- {\r
- if (copy_from_user(&index, (void __user *)arg, sizeof(index)))\r
- return -EFAULT;\r
- down_write(&vdm_rwsem);\r
- ret = vpu_mem_duplicate(file, index);\r
- up_write(&vdm_rwsem);\r
- break;\r
- }\r
- case VPU_MEM_LINK:\r
- DLOG("link\n");\r
- {\r
- if (copy_from_user(&index, (void __user *)arg, sizeof(index)))\r
- return -EFAULT;\r
- down_write(&vdm_rwsem);\r
- ret = vpu_mem_link(file, index);\r
- up_write(&vdm_rwsem);\r
- break;\r
- }\r
+ case VPU_MEM_CACHE_CLEAN:\r
+ case VPU_MEM_CACHE_INVALID: {\r
+ DLOG("flush\n");\r
+ if (copy_from_user(&index, (void __user *)arg, sizeof(index)))\r
+ return -EFAULT;\r
+ if (index < 0)\r
+ return -EINVAL;\r
+ vpu_mem_cache_opt(file, index, cmd);\r
+ } break;\r
+ case VPU_MEM_DUPLICATE: {\r
+ DLOG("duplicate\n");\r
+ if (copy_from_user(&index, (void __user *)arg, sizeof(index)))\r
+ return -EFAULT;\r
+ down_write(&vdm_rwsem);\r
+ ret = vpu_mem_duplicate(file, index);\r
+ up_write(&vdm_rwsem);\r
+ } break;\r
+\r
+ case VPU_MEM_LINK: {\r
+ DLOG("link\n");\r
+ if (copy_from_user(&index, (void __user *)arg, sizeof(index)))\r
+ return -EFAULT;\r
+ down_write(&vdm_rwsem);\r
+ ret = vpu_mem_link(file, index);\r
+ up_write(&vdm_rwsem);\r
+ } break;\r
+\r
+ case VPU_MEM_POOL_SET: {\r
+ struct vpu_mem_pool_config config;\r
+ DLOG("pool set\n");\r
+ if (copy_from_user(&config, (void __user *)arg, sizeof(config)))\r
+ return -EFAULT;\r
+ config.size = (config.size + VPU_MEM_MIN_ALLOC - 1)/VPU_MEM_MIN_ALLOC;\r
+ down_write(&vdm_rwsem);\r
+ ret = vpu_mem_pool_set(file, config.size, config.count);\r
+ up_write(&vdm_rwsem);\r
+ } break;\r
+\r
+ case VPU_MEM_POOL_UNSET: {\r
+ struct vpu_mem_pool_config config;\r
+ DLOG("pool unset\n");\r
+ if (copy_from_user(&config, (void __user *)arg, sizeof(config)))\r
+ return -EFAULT;\r
+ config.size = (config.size + VPU_MEM_MIN_ALLOC - 1)/VPU_MEM_MIN_ALLOC;\r
+ down_write(&vdm_rwsem);\r
+ ret = vpu_mem_pool_unset(file, config.size, config.count);\r
+ up_write(&vdm_rwsem);\r
+ } break;\r
+\r
+ case VPU_MEM_POOL_CHECK: {\r
+ int pfn;\r
+ if (copy_from_user(&pfn, (void __user *)arg, sizeof(int)))\r
+ return -EFAULT;\r
+ pfn = (pfn + VPU_MEM_MIN_ALLOC - 1)/VPU_MEM_MIN_ALLOC;\r
+ DLOG("pool check\n");\r
+ down_write(&vdm_rwsem);\r
+ ret = vpu_mem_pool_check(file, pfn);\r
+ up_write(&vdm_rwsem);\r
+ } break;\r
+\r
default:\r
return -EINVAL;\r
}\r
return ret;\r
}\r
\r
+struct file_operations vpu_mem_fops = {\r
+ .open = vpu_mem_open,\r
+ .mmap = vpu_mem_mmap,\r
+ .unlocked_ioctl = vpu_mem_ioctl,\r
+ .release = vpu_mem_release,\r
+};\r
+\r
#if VPU_MEM_DEBUG\r
static ssize_t debug_open(struct inode *inode, struct file *file)\r
{\r
down_read(&vdm_rwsem);\r
{\r
vdm_link *link, *tmp_link;\r
+ vdm_pool *pool, *tmp_pool;\r
vdm_region *region, *tmp_region;\r
vdm_session *session, *tmp_session;\r
// °´ index ´òÓ¡È«²¿ region\r
seq_printf(s, "free :\n");\r
list_for_each_entry_safe(link, tmp_link, &vdm_free, status_link) {\r
seq_printf(s, " idx %6d pfn %6d used %3d post %3d\n",\r
- link->index, link->pfn, link->link_used, link->link_post);\r
+ link->index, link->pfn, link->ref.used, link->ref.post);\r
}\r
}\r
if (list_empty(&vdm_used)) {\r
seq_printf(s, "used :\n");\r
list_for_each_entry_safe(link, tmp_link, &vdm_used, status_link) {\r
seq_printf(s, " idx %6d pfn %6d used %3d post %3d\n",\r
- link->index, link->pfn, link->link_used, link->link_post);\r
+ link->index, link->pfn, link->ref.used, link->ref.post);\r
}\r
}\r
if (list_empty(&vdm_post)) {\r
seq_printf(s, "post :\n");\r
list_for_each_entry_safe(link, tmp_link, &vdm_post, status_link) {\r
seq_printf(s, " idx %6d pfn %6d used %3d post %3d\n",\r
- link->index, link->pfn, link->link_used, link->link_post);\r
+ link->index, link->pfn, link->ref.used, link->ref.post);\r
}\r
}\r
\r
// ´òÓ¡ vpu_mem_info ÖеÄÈ«²¿ session µÄ region Õ¼ÓÃÇé¿ö\r
list_for_each_entry_safe(session, tmp_session, &vdm_proc, list_session) {\r
seq_printf(s, "\npid: %d\n", session->pid);\r
+ if (list_empty(&session->list_pool)) {\r
+ seq_printf(s, "pool : empty\n");\r
+ } else {\r
+ seq_printf(s, "pool :\n");\r
+ list_for_each_entry_safe(pool, tmp_pool, &session->list_pool, session_link) {\r
+ seq_printf(s, " pfn %6d target %4d current %2d\n",\r
+ pool->pfn, pool->count_target, pool->count_current);\r
+ }\r
+ }\r
if (list_empty(&session->list_used)) {\r
seq_printf(s, "used : empty\n");\r
} else {\r
seq_printf(s, "used :\n");\r
list_for_each_entry_safe(link, tmp_link, &session->list_used, session_link) {\r
seq_printf(s, " idx %6d pfn %6d used %3d\n",\r
- link->index, link->pfn, link->link_used);\r
+ link->index, link->pfn, link->ref.used);\r
}\r
}\r
if (list_empty(&session->list_post)) {\r
seq_printf(s, "post :\n");\r
list_for_each_entry_safe(link, tmp_link, &session->list_post, session_link) {\r
seq_printf(s, " idx %6d pfn %6d post %3d\n",\r
- link->index, link->pfn, link->link_post);\r
+ link->index, link->pfn, link->ref.post);\r
}\r
}\r
}\r