vpu: fix large resolution jpeg encode fault
authorljf <ljf@rock-chips.com>
Mon, 11 Aug 2014 09:50:08 +0000 (17:50 +0800)
committerljf <ljf@rock-chips.com>
Mon, 11 Aug 2014 09:50:08 +0000 (17:50 +0800)
arch/arm/mach-rockchip/vcodec_service.c

index 88aea8447f20ce3ebabafe83abbdc6efaba122bf..79e78a9222a2083c62a4eed2b713c31fb036449a 100755 (executable)
@@ -102,6 +102,19 @@ typedef struct {
        unsigned long           dec_io_size;\r
 } VPU_HW_INFO_E;\r
 \r
+struct extra_info_elem {\r
+       u32 index;\r
+       u32 offset;\r
+};\r
+\r
+#define EXTRA_INFO_MAGIC       0x4C4A46\r
+\r
+struct extra_info_for_iommu {\r
+       u32 magic;\r
+       u32 cnt;\r
+       struct extra_info_elem elem[20];\r
+};\r
+\r
 #define VPU_SERVICE_SHOW_TIME                  0\r
 \r
 #if VPU_SERVICE_SHOW_TIME\r
@@ -655,13 +668,15 @@ static inline enum VPU_DEC_FMT reg_check_fmt(vpu_reg *reg)
 \r
 static inline int reg_probe_width(vpu_reg *reg)\r
 {\r
-    int width_in_mb = reg->reg[4] >> 23;\r
-    \r
-    return width_in_mb * 16;\r
+       int width_in_mb = reg->reg[4] >> 23;\r
+\r
+       return width_in_mb * 16;\r
 }\r
 \r
 #if defined(CONFIG_VCODEC_MMU)\r
-static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, int size, vpu_reg *reg)\r
+static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl,\r
+                                                               int size, vpu_reg *reg,\r
+                                                               struct extra_info_for_iommu *ext_inf)\r
 {\r
        int i;\r
        int usr_fd = 0;\r
@@ -717,10 +732,20 @@ static int vcodec_bufid_to_iova(struct vpu_service_info *pservice, u8 *tbl, int
                        list_add_tail(&mem_region->reg_lnk, &reg->mem_region_list);\r
                }\r
        }\r
+\r
+       if (ext_inf != NULL && ext_inf->magic == EXTRA_INFO_MAGIC) {\r
+               for (i=0; i<ext_inf->cnt; i++) {\r
+                       pr_info("reg[%d] + offset %d\n", ext_inf->elem[i].index, ext_inf->elem[i].offset);\r
+                       reg->reg[ext_inf->elem[i].index] += ext_inf->elem[i].offset;\r
+               }\r
+       }\r
+\r
        return 0;\r
 }\r
 \r
-static int vcodec_reg_address_translate(struct vpu_service_info *pservice, vpu_reg *reg)\r
+static int vcodec_reg_address_translate(struct vpu_service_info *pservice,\r
+                                                                               vpu_reg *reg,\r
+                                                                               struct extra_info_for_iommu *ext_inf)\r
 {\r
        VPU_HW_ID hw_id;\r
        u8 *tbl;\r
@@ -779,7 +804,7 @@ static int vcodec_reg_address_translate(struct vpu_service_info *pservice, vpu_r
        }\r
 \r
        if (size != 0) {\r
-               return vcodec_bufid_to_iova(pservice, tbl, size, reg);\r
+               return vcodec_bufid_to_iova(pservice, tbl, size, reg, ext_inf);\r
        } else {\r
                return -1;\r
        }\r
@@ -788,6 +813,8 @@ static int vcodec_reg_address_translate(struct vpu_service_info *pservice, vpu_r
 \r
 static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session, void __user *src, unsigned long size)\r
 {\r
+       int extra_size = 0;\r
+       struct extra_info_for_iommu extra_info;\r
        vpu_reg *reg = kmalloc(sizeof(vpu_reg)+pservice->reg_size, GFP_KERNEL);\r
        if (NULL == reg) {\r
                pr_err("error: kmalloc fail in reg_init\n");\r
@@ -795,7 +822,9 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session
        }\r
 \r
        if (size > pservice->reg_size) {\r
-               printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size);\r
+               /*printk("warning: vpu reg size %lu is larger than hw reg size %lu\n", size, pservice->reg_size);\r
+               size = pservice->reg_size;*/\r
+               extra_size = size - pservice->reg_size;\r
                size = pservice->reg_size;\r
        }\r
        reg->session = session;\r
@@ -807,9 +836,9 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session
        INIT_LIST_HEAD(&reg->status_link);\r
 \r
 #if defined(CONFIG_VCODEC_MMU)  \r
-        if (pservice->mmu_dev) {\r
-            INIT_LIST_HEAD(&reg->mem_region_list);\r
-        }\r
+       if (pservice->mmu_dev) {\r
+               INIT_LIST_HEAD(&reg->mem_region_list);\r
+       }\r
 #endif\r
 \r
        if (copy_from_user(&reg->reg[0], (void __user *)src, size)) {\r
@@ -818,8 +847,14 @@ static vpu_reg *reg_init(struct vpu_service_info *pservice, vpu_session *session
                return NULL;\r
        }\r
 \r
+       if (copy_from_user(&extra_info, (u8 *)src + size, extra_size)) {\r
+               pr_err("error: copy_from_user failed in reg_init\n");\r
+               kfree(reg);\r
+               return NULL;\r
+       }\r
+\r
 #if defined(CONFIG_VCODEC_MMU)\r
-       if (pservice->mmu_dev && 0 > vcodec_reg_address_translate(pservice, reg)) {\r
+       if (pservice->mmu_dev && 0 > vcodec_reg_address_translate(pservice, reg, &extra_info)) {\r
                pr_err("error: translate reg address failed\n");\r
                kfree(reg);\r
                return NULL;\r