gdc: fix gdc buffer index error caused crash issue [1/2]
authorPengcheng Chen <pengcheng.chen@amlogic.com>
Thu, 14 Mar 2019 09:44:33 +0000 (17:44 +0800)
committerPengcheng Chen <pengcheng.chen@amlogic.com>
Wed, 20 Mar 2019 09:30:17 +0000 (17:30 +0800)
PD#SWPL-5685

Problem:
gdc buffer index error when dma alloc called simultaneously

Solution:
add lock to gdc buffer index

Verify:
verified by w400

Change-Id: Ia5e41562675b594029fd5a0166561c0069739536
Signed-off-by: Pengcheng Chen <pengcheng.chen@amlogic.com>
drivers/amlogic/media/gdc/app/gdc_dmabuf.c
drivers/amlogic/media/gdc/app/gdc_module.c

index 624fe7b..d215799 100644 (file)
@@ -54,7 +54,8 @@ static void aml_dma_put(void *buf_priv)
        clear_dma_buffer((struct aml_dma_buffer *)buf->priv, buf->index);
        put_device(buf->dev);
        kfree(buf);
-       gdc_log(LOG_INFO, "gdc aml_dma_put free!\n");
+       gdc_log(LOG_INFO, "gdc free:aml_dma_buf=0x%p,buf->index=%d\n",
+               buf, buf->index);
 }
 
 static void *aml_dma_alloc(struct device *dev, unsigned long attrs,
@@ -89,8 +90,8 @@ static void *aml_dma_alloc(struct device *dev, unsigned long attrs,
        buf->dma_dir = dma_dir;
 
        atomic_inc(&buf->refcount);
-       gdc_log(LOG_INFO, "aml_dma_alloc, refcont=%d\n",
-               atomic_read(&buf->refcount));
+       gdc_log(LOG_INFO, "aml_dma_buf=0x%p, refcont=%d\n",
+               buf, atomic_read(&buf->refcount));
 
        return buf;
 }
@@ -345,7 +346,11 @@ static int find_empty_dma_buffer(struct aml_dma_buffer *buffer)
 
 static void clear_dma_buffer(struct aml_dma_buffer *buffer, int index)
 {
+       mutex_lock(&(buffer->lock));
+       buffer->gd_buffer[index].mem_priv = NULL;
+       buffer->gd_buffer[index].index = 0;
        buffer->gd_buffer[index].alloc = 0;
+       mutex_unlock(&(buffer->lock));
 }
 
 void *gdc_dma_buffer_create(void)
@@ -375,6 +380,7 @@ int gdc_dma_buffer_alloc(struct aml_dma_buffer *buffer,
        struct device *dev,
        struct gdc_dmabuf_req_s *gdc_req_buf)
 {
+       struct aml_dma_buf *dma_buf;
        void *buf;
        unsigned int size;
        int index;
@@ -389,20 +395,23 @@ int gdc_dma_buffer_alloc(struct aml_dma_buffer *buffer,
        size = PAGE_ALIGN(gdc_req_buf->len);
        if (size == 0)
                return (-EINVAL);
-
+       buf = aml_dma_alloc(dev, 0, size, gdc_req_buf->dma_dir,
+               GFP_HIGHUSER | __GFP_ZERO);
+       if (!buf)
+               return (-ENOMEM);
+       dma_buf = (struct aml_dma_buf *)buf;
+       mutex_lock(&(buffer->lock));
        index = find_empty_dma_buffer(buffer);
        if ((index < 0) || (index >= AML_MAX_DMABUF)) {
                pr_err("no empty buffer found\n");
+               dma_free_attrs(dev, dma_buf->size, dma_buf->cookie,
+                              dma_buf->dma_addr,
+                              dma_buf->attrs);
+               mutex_unlock(&(buffer->lock));
                return (-ENOMEM);
        }
-
-       buf = aml_dma_alloc(dev, 0, size, gdc_req_buf->dma_dir,
-               GFP_HIGHUSER | __GFP_ZERO);
-       if (!buf)
-               return (-ENOMEM);
        ((struct aml_dma_buf *)buf)->priv = buffer;
        ((struct aml_dma_buf *)buf)->index = index;
-       mutex_lock(&(buffer->lock));
        buffer->gd_buffer[index].mem_priv = buf;
        buffer->gd_buffer[index].index = index;
        buffer->gd_buffer[index].alloc = 1;
@@ -452,7 +461,6 @@ int gdc_dma_buffer_export(struct aml_dma_buffer *buffer,
                pr_err("aml_dma_buf is null\n");
                return (-EINVAL);
        }
-
        dbuf = get_dmabuf(buf, flags & O_ACCMODE);
        if (IS_ERR_OR_NULL(dbuf)) {
                pr_err("failed to export buffer %d\n", index);
@@ -465,7 +473,6 @@ int gdc_dma_buffer_export(struct aml_dma_buffer *buffer,
                dma_buf_put(dbuf);
                return ret;
        }
-
        gdc_log(LOG_INFO, "buffer %d,exported as %d descriptor\n",
                index, ret);
        gdc_exp_buf->fd = ret;
@@ -491,21 +498,19 @@ int gdc_dma_buffer_map(struct aml_dma_cfg *cfg)
        fd = cfg->fd;
        dev = cfg->dev;
        dir = cfg->dir;
-
        dbuf = dma_buf_get(fd);
-       if (dbuf == NULL) {
+       if (IS_ERR(dbuf)) {
                pr_err("failed to get dma buffer");
                return -EINVAL;
        }
-
        d_att = dma_buf_attach(dbuf, dev);
-       if (d_att == NULL) {
+       if (IS_ERR(d_att)) {
                pr_err("failed to set dma attach");
                goto attach_err;
        }
 
        sg = dma_buf_map_attachment(d_att, dir);
-       if (sg == NULL) {
+       if (IS_ERR(sg)) {
                pr_err("failed to get dma sg");
                goto map_attach_err;
        }
@@ -540,7 +545,6 @@ map_attach_err:
 
 attach_err:
        dma_buf_put(dbuf);
-
        return ret;
 }
 
@@ -588,7 +592,6 @@ void gdc_dma_buffer_unmap(struct aml_dma_cfg *cfg)
        vaddr = cfg->vaddr;
        d_att = cfg->attach;
        sg = cfg->sg;
-
        dma_buf_vunmap(dbuf, vaddr);
 
        dma_buf_end_cpu_access(dbuf, dir);
index e698baf..657cd40 100644 (file)
@@ -551,6 +551,7 @@ static long gdc_process_input_dma_info(struct mgdc_fh_s *fh,
                        }
                        gdc_log(LOG_INFO, "1 plane get input addr=%x\n",
                                gdc_cmd->y_base_addr);
+                       gdc_buffer_dma_flush(gs_ex->input_buffer.shared_fd);
                } else if (gs_ex->input_buffer.plane_number == 2) {
                        cfg = &fh->dma_cfg.input_cfg_plane1;
                        cfg->fd = gs_ex->input_buffer.y_base_fd;
@@ -564,6 +565,7 @@ static long gdc_process_input_dma_info(struct mgdc_fh_s *fh,
                                return -EINVAL;
                        }
                        gdc_cmd->y_base_addr = addr;
+                       gdc_buffer_dma_flush(gs_ex->input_buffer.y_base_fd);
                        cfg = &fh->dma_cfg.input_cfg_plane2;
                        cfg->fd = gs_ex->input_buffer.uv_base_fd;
                        cfg->dev = &fh->gdev->pdev->dev;
@@ -576,6 +578,7 @@ static long gdc_process_input_dma_info(struct mgdc_fh_s *fh,
                                return -EINVAL;
                        }
                        gdc_cmd->uv_base_addr = addr;
+                       gdc_buffer_dma_flush(gs_ex->input_buffer.uv_base_fd);
                        gdc_log(LOG_INFO, "2 plane get input addr=%x\n",
                                gdc_cmd->y_base_addr);
                        gdc_log(LOG_INFO, "2 plane get input addr=%x\n",
@@ -596,6 +599,7 @@ static long gdc_process_input_dma_info(struct mgdc_fh_s *fh,
                }
                gdc_cmd->y_base_addr = addr;
                gdc_cmd->uv_base_addr = 0;
+               gdc_buffer_dma_flush(gs_ex->input_buffer.shared_fd);
        break;
        default:
                gdc_log(LOG_ERR, "Error image format");
@@ -691,7 +695,9 @@ static long gdc_process_ex_info(struct mgdc_fh_s *fh,
                }
        } else if (gs_ex->input_buffer.mem_alloc_type == AML_GDC_MEM_DMABUF) {
                /* dma alloc */
-               gdc_process_input_dma_info(fh, gs_ex);
+               ret = gdc_process_input_dma_info(fh, gs_ex);
+               if (ret < 0)
+                       return -EINVAL;
        }
        gdc_log(LOG_INFO, "%s, input addr=%x\n",
                __func__, fh->gdc_cmd.y_base_addr);
@@ -923,7 +929,7 @@ static long meson_gdc_ioctl(struct file *file, unsigned int cmd,
                        gdc_log(LOG_ERR, "copy from user failed\n");
                memcpy(&gdc_cmd->gdc_config, &gs_ex.gdc_config,
                        sizeof(struct gdc_config_s));
-               gdc_process_ex_info(fh, &gs_ex);
+               ret = gdc_process_ex_info(fh, &gs_ex);
                break;
        case GDC_REQUEST_DMA_BUFF:
                ret = copy_from_user(&gdc_req_buf, argp,