]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/exynos/exynos_drm_ipp.c
Merge branch 'upstream' of git://git.linux-mips.org/pub/scm/ralf/upstream-linus
[karo-tx-linux.git] / drivers / gpu / drm / exynos / exynos_drm_ipp.c
index 3d78144387ac6cf091a8434172c0654ef9f2f819..a1888e128f1d306e0c10934cb6042c83f4ce10e7 100644 (file)
@@ -167,6 +167,13 @@ static int ipp_create_id(struct idr *id_idr, struct mutex *lock, void *obj,
        return 0;
 }
 
+static void ipp_remove_id(struct idr *id_idr, struct mutex *lock, u32 id)
+{
+       mutex_lock(lock);
+       idr_remove(id_idr, id);
+       mutex_unlock(lock);
+}
+
 static void *ipp_find_obj(struct idr *id_idr, struct mutex *lock, u32 id)
 {
        void *obj;
@@ -276,11 +283,6 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id)
 
        DRM_DEBUG_KMS("prop_id[%d]\n", prop_id);
 
-       if (list_empty(&exynos_drm_ippdrv_list)) {
-               DRM_DEBUG_KMS("ippdrv_list is empty.\n");
-               return ERR_PTR(-ENODEV);
-       }
-
        /*
         * This case is search ipp driver by prop_id handle.
         * sometimes, ipp subsystem find driver by prop_id.
@@ -289,11 +291,14 @@ static struct exynos_drm_ippdrv *ipp_find_drv_by_handle(u32 prop_id)
        list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
                DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n", count++, (int)ippdrv);
 
-               if (!list_empty(&ippdrv->cmd_list)) {
-                       list_for_each_entry(c_node, &ippdrv->cmd_list, list)
-                               if (c_node->property.prop_id == prop_id)
-                                       return ippdrv;
+               mutex_lock(&ippdrv->cmd_lock);
+               list_for_each_entry(c_node, &ippdrv->cmd_list, list) {
+                       if (c_node->property.prop_id == prop_id) {
+                               mutex_unlock(&ippdrv->cmd_lock);
+                               return ippdrv;
+                       }
                }
+               mutex_unlock(&ippdrv->cmd_lock);
        }
 
        return ERR_PTR(-ENODEV);
@@ -325,6 +330,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
        if (!prop_list->ipp_id) {
                list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list)
                        count++;
+
                /*
                 * Supports ippdrv list count for user application.
                 * First step user application getting ippdrv count.
@@ -346,7 +352,7 @@ int exynos_drm_ipp_get_property(struct drm_device *drm_dev, void *data,
                        return PTR_ERR(ippdrv);
                }
 
-               prop_list = ippdrv->prop_list;
+               *prop_list = ippdrv->prop_list;
        }
 
        return 0;
@@ -386,9 +392,11 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property)
         * when we find this command no using prop_id.
         * return property information set in this command node.
         */
+       mutex_lock(&ippdrv->cmd_lock);
        list_for_each_entry(c_node, &ippdrv->cmd_list, list) {
                if ((c_node->property.prop_id == prop_id) &&
                    (c_node->state == IPP_STATE_STOP)) {
+                       mutex_unlock(&ippdrv->cmd_lock);
                        DRM_DEBUG_KMS("found cmd[%d]ippdrv[0x%x]\n",
                                property->cmd, (int)ippdrv);
 
@@ -396,6 +404,7 @@ static int ipp_find_and_set_property(struct drm_exynos_ipp_property *property)
                        return 0;
                }
        }
+       mutex_unlock(&ippdrv->cmd_lock);
 
        DRM_ERROR("failed to search property.\n");
 
@@ -499,7 +508,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
        c_node->start_work = ipp_create_cmd_work();
        if (IS_ERR(c_node->start_work)) {
                DRM_ERROR("failed to create start work.\n");
-               goto err_clear;
+               goto err_remove_id;
        }
 
        c_node->stop_work = ipp_create_cmd_work();
@@ -514,7 +523,7 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
                goto err_free_stop;
        }
 
-       mutex_init(&c_node->cmd_lock);
+       mutex_init(&c_node->lock);
        mutex_init(&c_node->mem_lock);
        mutex_init(&c_node->event_lock);
 
@@ -526,7 +535,9 @@ int exynos_drm_ipp_set_property(struct drm_device *drm_dev, void *data,
 
        INIT_LIST_HEAD(&c_node->event_list);
        list_splice_init(&priv->event_list, &c_node->event_list);
+       mutex_lock(&ippdrv->cmd_lock);
        list_add_tail(&c_node->list, &ippdrv->cmd_list);
+       mutex_unlock(&ippdrv->cmd_lock);
 
        /* make dedicated state without m2m */
        if (!ipp_is_m2m_cmd(property->cmd))
@@ -538,18 +549,24 @@ err_free_stop:
        kfree(c_node->stop_work);
 err_free_start:
        kfree(c_node->start_work);
+err_remove_id:
+       ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock, property->prop_id);
 err_clear:
        kfree(c_node);
        return ret;
 }
 
-static void ipp_clean_cmd_node(struct drm_exynos_ipp_cmd_node *c_node)
+static void ipp_clean_cmd_node(struct ipp_context *ctx,
+                               struct drm_exynos_ipp_cmd_node *c_node)
 {
        /* delete list */
        list_del(&c_node->list);
 
+       ipp_remove_id(&ctx->prop_idr, &ctx->prop_lock,
+                       c_node->property.prop_id);
+
        /* destroy mutex */
-       mutex_destroy(&c_node->cmd_lock);
+       mutex_destroy(&c_node->lock);
        mutex_destroy(&c_node->mem_lock);
        mutex_destroy(&c_node->event_lock);
 
@@ -567,17 +584,10 @@ static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node)
        struct list_head *head;
        int ret, i, count[EXYNOS_DRM_OPS_MAX] = { 0, };
 
-       mutex_lock(&c_node->mem_lock);
-
        for_each_ipp_ops(i) {
                /* source/destination memory list */
                head = &c_node->mem_list[i];
 
-               if (list_empty(head)) {
-                       DRM_DEBUG_KMS("%s memory empty.\n", i ? "dst" : "src");
-                       continue;
-               }
-
                /* find memory node entry */
                list_for_each_entry(m_node, head, list) {
                        DRM_DEBUG_KMS("%s,count[%d]m_node[0x%x]\n",
@@ -602,8 +612,6 @@ static int ipp_check_mem_list(struct drm_exynos_ipp_cmd_node *c_node)
                ret = max(count[EXYNOS_DRM_OPS_SRC],
                        count[EXYNOS_DRM_OPS_DST]);
 
-       mutex_unlock(&c_node->mem_lock);
-
        return ret;
 }
 
@@ -646,16 +654,13 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
                return -EFAULT;
        }
 
-       mutex_lock(&c_node->mem_lock);
-
        DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
 
        /* get operations callback */
        ops = ippdrv->ops[m_node->ops_id];
        if (!ops) {
                DRM_ERROR("not support ops.\n");
-               ret = -EFAULT;
-               goto err_unlock;
+               return -EFAULT;
        }
 
        /* set address and enable irq */
@@ -664,12 +669,10 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
                        m_node->buf_id, IPP_BUF_ENQUEUE);
                if (ret) {
                        DRM_ERROR("failed to set addr.\n");
-                       goto err_unlock;
+                       return ret;
                }
        }
 
-err_unlock:
-       mutex_unlock(&c_node->mem_lock);
        return ret;
 }
 
@@ -684,11 +687,9 @@ static struct drm_exynos_ipp_mem_node
        void *addr;
        int i;
 
-       mutex_lock(&c_node->mem_lock);
-
        m_node = kzalloc(sizeof(*m_node), GFP_KERNEL);
        if (!m_node)
-               goto err_unlock;
+               return ERR_PTR(-ENOMEM);
 
        /* clear base address for error handling */
        memset(&buf_info, 0x0, sizeof(buf_info));
@@ -722,15 +723,14 @@ static struct drm_exynos_ipp_mem_node
 
        m_node->filp = file;
        m_node->buf_info = buf_info;
+       mutex_lock(&c_node->mem_lock);
        list_add_tail(&m_node->list, &c_node->mem_list[qbuf->ops_id]);
-
        mutex_unlock(&c_node->mem_lock);
+
        return m_node;
 
 err_clear:
        kfree(m_node);
-err_unlock:
-       mutex_unlock(&c_node->mem_lock);
        return ERR_PTR(-EFAULT);
 }
 
@@ -747,13 +747,6 @@ static int ipp_put_mem_node(struct drm_device *drm_dev,
                return -EFAULT;
        }
 
-       if (list_empty(&m_node->list)) {
-               DRM_ERROR("empty memory node.\n");
-               return -ENOMEM;
-       }
-
-       mutex_lock(&c_node->mem_lock);
-
        DRM_DEBUG_KMS("ops_id[%d]\n", m_node->ops_id);
 
        /* put gem buffer */
@@ -768,8 +761,6 @@ static int ipp_put_mem_node(struct drm_device *drm_dev,
        list_del(&m_node->list);
        kfree(m_node);
 
-       mutex_unlock(&c_node->mem_lock);
-
        return 0;
 }
 
@@ -805,7 +796,9 @@ static int ipp_get_event(struct drm_device *drm_dev,
        e->base.event = &e->event.base;
        e->base.file_priv = file;
        e->base.destroy = ipp_free_event;
+       mutex_lock(&c_node->event_lock);
        list_add_tail(&e->base.link, &c_node->event_list);
+       mutex_unlock(&c_node->event_lock);
 
        return 0;
 }
@@ -816,11 +809,7 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,
        struct drm_exynos_ipp_send_event *e, *te;
        int count = 0;
 
-       if (list_empty(&c_node->event_list)) {
-               DRM_DEBUG_KMS("event_list is empty.\n");
-               return;
-       }
-
+       mutex_lock(&c_node->event_lock);
        list_for_each_entry_safe(e, te, &c_node->event_list, base.link) {
                DRM_DEBUG_KMS("count[%d]e[0x%x]\n", count++, (int)e);
 
@@ -841,9 +830,13 @@ static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node,
                        /* delete list */
                        list_del(&e->base.link);
                        kfree(e);
-                       return;
+                       goto out_unlock;
                }
        }
+
+out_unlock:
+       mutex_unlock(&c_node->event_lock);
+       return;
 }
 
 static void ipp_handle_cmd_work(struct device *dev,
@@ -887,7 +880,9 @@ static int ipp_queue_buf_with_run(struct device *dev,
                return 0;
        }
 
+       mutex_lock(&c_node->mem_lock);
        if (!ipp_check_mem_list(c_node)) {
+               mutex_unlock(&c_node->mem_lock);
                DRM_DEBUG_KMS("empty memory.\n");
                return 0;
        }
@@ -904,10 +899,12 @@ static int ipp_queue_buf_with_run(struct device *dev,
        } else {
                ret = ipp_set_mem_node(ippdrv, c_node, m_node);
                if (ret) {
+                       mutex_unlock(&c_node->mem_lock);
                        DRM_ERROR("failed to set m node.\n");
                        return ret;
                }
        }
+       mutex_unlock(&c_node->mem_lock);
 
        return 0;
 }
@@ -918,15 +915,15 @@ static void ipp_clean_queue_buf(struct drm_device *drm_dev,
 {
        struct drm_exynos_ipp_mem_node *m_node, *tm_node;
 
-       if (!list_empty(&c_node->mem_list[qbuf->ops_id])) {
-               /* delete list */
-               list_for_each_entry_safe(m_node, tm_node,
-                       &c_node->mem_list[qbuf->ops_id], list) {
-                       if (m_node->buf_id == qbuf->buf_id &&
-                           m_node->ops_id == qbuf->ops_id)
-                               ipp_put_mem_node(drm_dev, c_node, m_node);
-               }
+       /* delete list */
+       mutex_lock(&c_node->mem_lock);
+       list_for_each_entry_safe(m_node, tm_node,
+               &c_node->mem_list[qbuf->ops_id], list) {
+               if (m_node->buf_id == qbuf->buf_id &&
+                   m_node->ops_id == qbuf->ops_id)
+                       ipp_put_mem_node(drm_dev, c_node, m_node);
        }
+       mutex_unlock(&c_node->mem_lock);
 }
 
 int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
@@ -998,7 +995,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
                }
                break;
        case IPP_BUF_DEQUEUE:
-               mutex_lock(&c_node->cmd_lock);
+               mutex_lock(&c_node->lock);
 
                /* put event for destination buffer */
                if (qbuf->ops_id == EXYNOS_DRM_OPS_DST)
@@ -1006,7 +1003,7 @@ int exynos_drm_ipp_queue_buf(struct drm_device *drm_dev, void *data,
 
                ipp_clean_queue_buf(drm_dev, c_node, qbuf);
 
-               mutex_unlock(&c_node->cmd_lock);
+               mutex_unlock(&c_node->lock);
                break;
        default:
                DRM_ERROR("invalid buffer control.\n");
@@ -1109,12 +1106,12 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
        case IPP_CTRL_PLAY:
                if (pm_runtime_suspended(ippdrv->dev))
                        pm_runtime_get_sync(ippdrv->dev);
+
                c_node->state = IPP_STATE_START;
 
                cmd_work = c_node->start_work;
                cmd_work->ctrl = cmd_ctrl->ctrl;
                ipp_handle_cmd_work(dev, ippdrv, cmd_work, c_node);
-               c_node->state = IPP_STATE_START;
                break;
        case IPP_CTRL_STOP:
                cmd_work = c_node->stop_work;
@@ -1129,10 +1126,12 @@ int exynos_drm_ipp_cmd_ctrl(struct drm_device *drm_dev, void *data,
 
                c_node->state = IPP_STATE_STOP;
                ippdrv->dedicated = false;
-               ipp_clean_cmd_node(c_node);
+               mutex_lock(&ippdrv->cmd_lock);
+               ipp_clean_cmd_node(ctx, c_node);
 
                if (list_empty(&ippdrv->cmd_list))
                        pm_runtime_put_sync(ippdrv->dev);
+               mutex_unlock(&ippdrv->cmd_lock);
                break;
        case IPP_CTRL_PAUSE:
                cmd_work = c_node->stop_work;
@@ -1260,9 +1259,11 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
        /* store command info in ippdrv */
        ippdrv->c_node = c_node;
 
+       mutex_lock(&c_node->mem_lock);
        if (!ipp_check_mem_list(c_node)) {
                DRM_DEBUG_KMS("empty memory.\n");
-               return -ENOMEM;
+               ret = -ENOMEM;
+               goto err_unlock;
        }
 
        /* set current property in ippdrv */
@@ -1270,7 +1271,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
        if (ret) {
                DRM_ERROR("failed to set property.\n");
                ippdrv->c_node = NULL;
-               return ret;
+               goto err_unlock;
        }
 
        /* check command */
@@ -1285,7 +1286,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
                        if (!m_node) {
                                DRM_ERROR("failed to get node.\n");
                                ret = -EFAULT;
-                               return ret;
+                               goto err_unlock;
                        }
 
                        DRM_DEBUG_KMS("m_node[0x%x]\n", (int)m_node);
@@ -1293,7 +1294,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
                        ret = ipp_set_mem_node(ippdrv, c_node, m_node);
                        if (ret) {
                                DRM_ERROR("failed to set m node.\n");
-                               return ret;
+                               goto err_unlock;
                        }
                }
                break;
@@ -1305,7 +1306,7 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
                        ret = ipp_set_mem_node(ippdrv, c_node, m_node);
                        if (ret) {
                                DRM_ERROR("failed to set m node.\n");
-                               return ret;
+                               goto err_unlock;
                        }
                }
                break;
@@ -1317,14 +1318,16 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
                        ret = ipp_set_mem_node(ippdrv, c_node, m_node);
                        if (ret) {
                                DRM_ERROR("failed to set m node.\n");
-                               return ret;
+                               goto err_unlock;
                        }
                }
                break;
        default:
                DRM_ERROR("invalid operations.\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_unlock;
        }
+       mutex_unlock(&c_node->mem_lock);
 
        DRM_DEBUG_KMS("cmd[%d]\n", property->cmd);
 
@@ -1333,11 +1336,17 @@ static int ipp_start_property(struct exynos_drm_ippdrv *ippdrv,
                ret = ippdrv->start(ippdrv->dev, property->cmd);
                if (ret) {
                        DRM_ERROR("failed to start ops.\n");
+                       ippdrv->c_node = NULL;
                        return ret;
                }
        }
 
        return 0;
+
+err_unlock:
+       mutex_unlock(&c_node->mem_lock);
+       ippdrv->c_node = NULL;
+       return ret;
 }
 
 static int ipp_stop_property(struct drm_device *drm_dev,
@@ -1354,6 +1363,8 @@ static int ipp_stop_property(struct drm_device *drm_dev,
        /* put event */
        ipp_put_event(c_node, NULL);
 
+       mutex_lock(&c_node->mem_lock);
+
        /* check command */
        switch (property->cmd) {
        case IPP_CMD_M2M:
@@ -1361,11 +1372,6 @@ static int ipp_stop_property(struct drm_device *drm_dev,
                        /* source/destination memory list */
                        head = &c_node->mem_list[i];
 
-                       if (list_empty(head)) {
-                               DRM_DEBUG_KMS("mem_list is empty.\n");
-                               break;
-                       }
-
                        list_for_each_entry_safe(m_node, tm_node,
                                head, list) {
                                ret = ipp_put_mem_node(drm_dev, c_node,
@@ -1381,11 +1387,6 @@ static int ipp_stop_property(struct drm_device *drm_dev,
                /* destination memory list */
                head = &c_node->mem_list[EXYNOS_DRM_OPS_DST];
 
-               if (list_empty(head)) {
-                       DRM_DEBUG_KMS("mem_list is empty.\n");
-                       break;
-               }
-
                list_for_each_entry_safe(m_node, tm_node, head, list) {
                        ret = ipp_put_mem_node(drm_dev, c_node, m_node);
                        if (ret) {
@@ -1398,11 +1399,6 @@ static int ipp_stop_property(struct drm_device *drm_dev,
                /* source memory list */
                head = &c_node->mem_list[EXYNOS_DRM_OPS_SRC];
 
-               if (list_empty(head)) {
-                       DRM_DEBUG_KMS("mem_list is empty.\n");
-                       break;
-               }
-
                list_for_each_entry_safe(m_node, tm_node, head, list) {
                        ret = ipp_put_mem_node(drm_dev, c_node, m_node);
                        if (ret) {
@@ -1418,6 +1414,8 @@ static int ipp_stop_property(struct drm_device *drm_dev,
        }
 
 err_clear:
+       mutex_unlock(&c_node->mem_lock);
+
        /* stop operations */
        if (ippdrv->stop)
                ippdrv->stop(ippdrv->dev, property->cmd);
@@ -1446,7 +1444,7 @@ void ipp_sched_cmd(struct work_struct *work)
                return;
        }
 
-       mutex_lock(&c_node->cmd_lock);
+       mutex_lock(&c_node->lock);
 
        property = &c_node->property;
 
@@ -1494,7 +1492,7 @@ void ipp_sched_cmd(struct work_struct *work)
        DRM_DEBUG_KMS("ctrl[%d] done.\n", cmd_work->ctrl);
 
 err_unlock:
-       mutex_unlock(&c_node->cmd_lock);
+       mutex_unlock(&c_node->lock);
 }
 
 static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
@@ -1524,14 +1522,18 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
                return -EINVAL;
        }
 
+       mutex_lock(&c_node->event_lock);
        if (list_empty(&c_node->event_list)) {
                DRM_DEBUG_KMS("event list is empty.\n");
-               return 0;
+               ret = 0;
+               goto err_event_unlock;
        }
 
+       mutex_lock(&c_node->mem_lock);
        if (!ipp_check_mem_list(c_node)) {
                DRM_DEBUG_KMS("empty memory.\n");
-               return 0;
+               ret = 0;
+               goto err_mem_unlock;
        }
 
        /* check command */
@@ -1545,7 +1547,8 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
                                struct drm_exynos_ipp_mem_node, list);
                        if (!m_node) {
                                DRM_ERROR("empty memory node.\n");
-                               return -ENOMEM;
+                               ret = -ENOMEM;
+                               goto err_mem_unlock;
                        }
 
                        tbuf_id[i] = m_node->buf_id;
@@ -1567,7 +1570,8 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
                m_node = ipp_find_mem_node(c_node, &qbuf);
                if (!m_node) {
                        DRM_ERROR("empty memory node.\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto err_mem_unlock;
                }
 
                tbuf_id[EXYNOS_DRM_OPS_DST] = m_node->buf_id;
@@ -1584,7 +1588,8 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
                        struct drm_exynos_ipp_mem_node, list);
                if (!m_node) {
                        DRM_ERROR("empty memory node.\n");
-                       return -ENOMEM;
+                       ret = -ENOMEM;
+                       goto err_mem_unlock;
                }
 
                tbuf_id[EXYNOS_DRM_OPS_SRC] = m_node->buf_id;
@@ -1595,8 +1600,10 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
                break;
        default:
                DRM_ERROR("invalid operations.\n");
-               return -EINVAL;
+               ret = -EINVAL;
+               goto err_mem_unlock;
        }
+       mutex_unlock(&c_node->mem_lock);
 
        if (tbuf_id[EXYNOS_DRM_OPS_DST] != buf_id[EXYNOS_DRM_OPS_DST])
                DRM_ERROR("failed to match buf_id[%d %d]prop_id[%d]\n",
@@ -1611,11 +1618,6 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
        e = list_first_entry(&c_node->event_list,
                struct drm_exynos_ipp_send_event, base.link);
 
-       if (!e) {
-               DRM_ERROR("empty event.\n");
-               return -EINVAL;
-       }
-
        do_gettimeofday(&now);
        DRM_DEBUG_KMS("tv_sec[%ld]tv_usec[%ld]\n", now.tv_sec, now.tv_usec);
        e->event.tv_sec = now.tv_sec;
@@ -1630,11 +1632,18 @@ static int ipp_send_event(struct exynos_drm_ippdrv *ippdrv,
        list_move_tail(&e->base.link, &e->base.file_priv->event_list);
        wake_up_interruptible(&e->base.file_priv->event_wait);
        spin_unlock_irqrestore(&drm_dev->event_lock, flags);
+       mutex_unlock(&c_node->event_lock);
 
        DRM_DEBUG_KMS("done cmd[%d]prop_id[%d]buf_id[%d]\n",
                property->cmd, property->prop_id, tbuf_id[EXYNOS_DRM_OPS_DST]);
 
        return 0;
+
+err_mem_unlock:
+       mutex_unlock(&c_node->mem_lock);
+err_event_unlock:
+       mutex_unlock(&c_node->event_lock);
+       return ret;
 }
 
 void ipp_sched_event(struct work_struct *work)
@@ -1676,8 +1685,6 @@ void ipp_sched_event(struct work_struct *work)
                goto err_completion;
        }
 
-       mutex_lock(&c_node->event_lock);
-
        ret = ipp_send_event(ippdrv, c_node, event_work->buf_id);
        if (ret) {
                DRM_ERROR("failed to send event.\n");
@@ -1687,8 +1694,6 @@ void ipp_sched_event(struct work_struct *work)
 err_completion:
        if (ipp_is_m2m_cmd(c_node->property.cmd))
                complete(&c_node->start_complete);
-
-       mutex_unlock(&c_node->event_lock);
 }
 
 static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
@@ -1699,23 +1704,21 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
 
        /* get ipp driver entry */
        list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
+               u32 ipp_id;
+
                ippdrv->drm_dev = drm_dev;
 
                ret = ipp_create_id(&ctx->ipp_idr, &ctx->ipp_lock, ippdrv,
-                       &ippdrv->ipp_id);
-               if (ret) {
+                                   &ipp_id);
+               if (ret || ipp_id == 0) {
                        DRM_ERROR("failed to create id.\n");
-                       goto err_idr;
+                       goto err;
                }
 
                DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]ipp_id[%d]\n",
-                       count++, (int)ippdrv, ippdrv->ipp_id);
+                       count++, (int)ippdrv, ipp_id);
 
-               if (ippdrv->ipp_id == 0) {
-                       DRM_ERROR("failed to get ipp_id[%d]\n",
-                               ippdrv->ipp_id);
-                       goto err_idr;
-               }
+               ippdrv->prop_list.ipp_id = ipp_id;
 
                /* store parent device for node */
                ippdrv->parent_dev = dev;
@@ -1724,39 +1727,46 @@ static int ipp_subdrv_probe(struct drm_device *drm_dev, struct device *dev)
                ippdrv->event_workq = ctx->event_workq;
                ippdrv->sched_event = ipp_sched_event;
                INIT_LIST_HEAD(&ippdrv->cmd_list);
+               mutex_init(&ippdrv->cmd_lock);
 
                if (is_drm_iommu_supported(drm_dev)) {
                        ret = drm_iommu_attach_device(drm_dev, ippdrv->dev);
                        if (ret) {
                                DRM_ERROR("failed to activate iommu\n");
-                               goto err_iommu;
+                               goto err;
                        }
                }
        }
 
        return 0;
 
-err_iommu:
+err:
        /* get ipp driver entry */
-       list_for_each_entry_reverse(ippdrv, &exynos_drm_ippdrv_list, drv_list)
+       list_for_each_entry_continue_reverse(ippdrv, &exynos_drm_ippdrv_list,
+                                               drv_list) {
                if (is_drm_iommu_supported(drm_dev))
                        drm_iommu_detach_device(drm_dev, ippdrv->dev);
 
-err_idr:
-       idr_destroy(&ctx->ipp_idr);
-       idr_destroy(&ctx->prop_idr);
+               ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock,
+                               ippdrv->prop_list.ipp_id);
+       }
+
        return ret;
 }
 
 static void ipp_subdrv_remove(struct drm_device *drm_dev, struct device *dev)
 {
        struct exynos_drm_ippdrv *ippdrv;
+       struct ipp_context *ctx = get_ipp_context(dev);
 
        /* get ipp driver entry */
        list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
                if (is_drm_iommu_supported(drm_dev))
                        drm_iommu_detach_device(drm_dev, ippdrv->dev);
 
+               ipp_remove_id(&ctx->ipp_idr, &ctx->ipp_lock,
+                               ippdrv->prop_list.ipp_id);
+
                ippdrv->drm_dev = NULL;
                exynos_drm_ippdrv_unregister(ippdrv);
        }
@@ -1787,20 +1797,14 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,
        struct drm_exynos_file_private *file_priv = file->driver_priv;
        struct exynos_drm_ipp_private *priv = file_priv->ipp_priv;
        struct exynos_drm_ippdrv *ippdrv = NULL;
+       struct ipp_context *ctx = get_ipp_context(dev);
        struct drm_exynos_ipp_cmd_node *c_node, *tc_node;
        int count = 0;
 
        DRM_DEBUG_KMS("for priv[0x%x]\n", (int)priv);
 
-       if (list_empty(&exynos_drm_ippdrv_list)) {
-               DRM_DEBUG_KMS("ippdrv_list is empty.\n");
-               goto err_clear;
-       }
-
        list_for_each_entry(ippdrv, &exynos_drm_ippdrv_list, drv_list) {
-               if (list_empty(&ippdrv->cmd_list))
-                       continue;
-
+               mutex_lock(&ippdrv->cmd_lock);
                list_for_each_entry_safe(c_node, tc_node,
                        &ippdrv->cmd_list, list) {
                        DRM_DEBUG_KMS("count[%d]ippdrv[0x%x]\n",
@@ -1820,14 +1824,14 @@ static void ipp_subdrv_close(struct drm_device *drm_dev, struct device *dev,
                                }
 
                                ippdrv->dedicated = false;
-                               ipp_clean_cmd_node(c_node);
+                               ipp_clean_cmd_node(ctx, c_node);
                                if (list_empty(&ippdrv->cmd_list))
                                        pm_runtime_put_sync(ippdrv->dev);
                        }
                }
+               mutex_unlock(&ippdrv->cmd_lock);
        }
 
-err_clear:
        kfree(priv);
        return;
 }