rk29: vpu_mem: fix bug when link inner-process region
author陈恒明 <chm@rock-chips.com>
Thu, 16 Dec 2010 08:31:50 +0000 (00:31 -0800)
committer陈恒明 <chm@rock-chips.com>
Thu, 16 Dec 2010 08:35:30 +0000 (00:35 -0800)
arch/arm/mach-rk29/vpu_mem.c

index c88cbadd7471b79f355a9330b1f0cccfc91223bf..e9114e0c8cc21778b016c30f24e6528ac8dcd625 100644 (file)
@@ -252,11 +252,11 @@ static int region_check(int index)
 }\r
 \r
 /*\r
- * split allocated block from free block\r
+ * split new allocated block from free block\r
  * the bitmap_sem and region_list_sem must be hold together\r
  * the pnode is a ouput region node\r
  */\r
-static int region_split(struct list_head *region_list, struct vpu_mem_region_node *node, int index, int pfn)\r
+static int region_new(struct list_head *region_list, int index, int pfn)\r
 {\r
     int pfn_free = VPU_MEM_PFN(index);\r
     // check pfn is smaller then target index region\r
@@ -274,8 +274,9 @@ static int region_split(struct list_head *region_list, struct vpu_mem_region_nod
         return -EINVAL;\r
     }\r
 \r
-    if (NULL == node) {\r
+    {\r
         struct list_head *last;\r
+        struct vpu_mem_region_node *node;\r
         // check target index region first\r
         if (!VPU_MEM_IS_FREE(index)) {\r
 #if VPU_MEM_DEBUG\r
@@ -310,12 +311,58 @@ static int region_split(struct list_head *region_list, struct vpu_mem_region_nod
 \r
         region_set_avail(index, VPU_MEM_AVAIL(index) + 1);\r
         region_set_ref_count(index, VPU_MEM_REFC(index) + 1);\r
+        node->region.index = index;\r
+        node->region.ref_count = 1;\r
+    }\r
+\r
+    return 0;\r
+}\r
+\r
+/*\r
+ * link allocated block from free block\r
+ * the bitmap_sem and region_list_sem must be hold together\r
+ * the pnode is a ouput region node\r
+ */\r
+static int region_link(struct list_head *region_list, int index)\r
+{\r
+    struct vpu_mem_region_node *node = NULL;\r
+    struct list_head *list, *tmp;\r
+    list_for_each_safe(list, tmp, region_list) {\r
+        struct vpu_mem_region_node *p = list_entry(list, struct vpu_mem_region_node, list);\r
+        if (index == NODE_REGION_INDEX(p)) {\r
+            node = p;\r
+            break;\r
+        }\r
+    }\r
+\r
+    if (NULL == node) {\r
+        struct list_head *last;\r
+        DLOG("link non-exists index %d\n", index);\r
+\r
+        // malloc vpu_mem_region_node\r
+        node = kmalloc(sizeof(struct vpu_mem_region_node), GFP_KERNEL);\r
+        if (NULL == node) {\r
+#if VPU_MEM_DEBUG\r
+            printk(KERN_INFO "No space to allocate struct vpu_mem_region_node!");\r
+#endif\r
+            return -ENOMEM;\r
+        }\r
+\r
+        // search the last node\r
+        DLOG("search the last node\n");\r
+        for (last = region_list; !list_is_last(last, region_list);)\r
+            last = last->next;\r
+\r
+        DLOG("list_add_tail\n");\r
+        list_add_tail(&node->list, last);\r
+\r
         node->region.index = index;\r
         node->region.ref_count = 1;\r
     } else {\r
-        region_set_ref_count(index, VPU_MEM_REFC(index) + 1);\r
+        DLOG("link existed index %d\n", index);\r
         node->region.ref_count++;\r
     }\r
+    region_set_ref_count(index, VPU_MEM_REFC(index) + 1);\r
 \r
     return 0;\r
 }\r
@@ -391,11 +438,11 @@ static long vpu_mem_allocate(struct file *file, unsigned int len)
                        }\r
                }\r
 #if VPU_MEM_DEBUG\r
-        printk(KERN_INFO "vpu_mem: search curr %d\n!", curr);\r
+        //printk(KERN_INFO "vpu_mem: search curr %d\n!", curr);\r
 #endif\r
                curr = VPU_MEM_NEXT_INDEX(curr);\r
 #if VPU_MEM_DEBUG\r
-        printk(KERN_INFO "vpu_mem: search next %d\n!", curr);\r
+        //printk(KERN_INFO "vpu_mem: search next %d\n!", curr);\r
 #endif\r
        }\r
 \r
@@ -413,7 +460,7 @@ static long vpu_mem_allocate(struct file *file, unsigned int len)
 \r
     down_write(&data->sem);\r
     {\r
-        int ret = region_split(&data->region_list, NULL, best_fit, pfn);\r
+        int ret = region_new(&data->region_list, best_fit, pfn);\r
         if (ret)\r
             best_fit = -1;\r
     }\r
@@ -518,6 +565,7 @@ static int vpu_mem_duplicate(struct file *file, int index)
 \r
 static int vpu_mem_link(struct file *file, int index)\r
 {\r
+    int err;\r
     struct vpu_mem_data *data = (struct vpu_mem_data *)file->private_data;\r
 \r
        if (!is_vpu_mem_file(file)) {\r
@@ -534,26 +582,21 @@ static int vpu_mem_link(struct file *file, int index)
         return -EINVAL;\r
     }\r
 \r
-       /* caller should hold the write lock on vpu_mem_sem! */\r
-       DLOG("link index %d\n", index);\r
+    // check target index region first\r
+    if (VPU_MEM_IS_FREE(index)) {\r
+#if VPU_MEM_DEBUG\r
+        printk(KERN_INFO "try to link free region %d!", index);\r
+#endif\r
+        return -1;\r
+    }\r
 \r
+       /* caller should hold the write lock on vpu_mem_sem! */\r
        down_write(&data->sem);\r
-    {   // search exists index\r
-        struct list_head *list, *tmp;\r
-        list_for_each_safe(list, tmp, &data->region_list) {\r
-               struct vpu_mem_region_node *node = list_entry(list, struct vpu_mem_region_node, list);\r
-            if (index == NODE_REGION_INDEX(node)) {\r
-                region_split(&data->region_list, node, index, VPU_MEM_PFN(index));\r
-                up_write(&data->sem);\r
-                return 0;\r
-            }\r
-        }\r
-        // non-exists index\r
-        region_split(&data->region_list, NULL, index, VPU_MEM_PFN(index));\r
-       }\r
+    err = region_link(&data->region_list, index);\r
        up_write(&data->sem);\r
+    DLOG("link index %d ret %d\n", index, err);\r
 \r
-       return 0;\r
+       return err;\r
 }\r
 \r
 void vpu_mem_flush(struct file *file, long index)\r