diff options
author | Andrzej Hajda <a.hajda@samsung.com> | 2014-08-28 11:07:35 +0200 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-11-18 12:00:46 +0900 |
commit | a646017c2cf2eb8ff968c5362d26af5491d44f97 (patch) | |
tree | 1b669867de8263d77b7ee0996da82568785ed1d1 /drivers/gpu/drm | |
parent | 3819e4d918c2cffcf473153119f3fb113e2612c4 (diff) | |
download | linux-3.10-a646017c2cf2eb8ff968c5362d26af5491d44f97.tar.gz linux-3.10-a646017c2cf2eb8ff968c5362d26af5491d44f97.tar.bz2 linux-3.10-a646017c2cf2eb8ff968c5362d26af5491d44f97.zip |
drm/exynos/ipp: remove events during command cleaning
Events were removed only during stop command, as a result
there were memory leaks if program prematurely exited.
This patch fixes it.
Change-Id: I763b05753eb6bebe7ac3dc74da76dd08b5972142
Signed-off-by: Andrzej Hajda <a.hajda@samsung.com>
Reviewed-by: Joonyoung Shim <jy0922.shim@samsung.com>
Signed-off-by: Inki Dae <inki.dae@samsung.com>
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r-- | drivers/gpu/drm/exynos/exynos_drm_ipp.c | 156 |
1 files changed, 78 insertions, 78 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c index 53262563265..734a99944eb 100644 --- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c +++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c @@ -668,6 +668,81 @@ static void ipp_clean_mem_nodes(struct drm_device *drm_dev, mutex_unlock(&c_node->mem_lock); } +static void ipp_free_event(struct drm_pending_event *event) +{ + kfree(event); +} + +static int ipp_get_event(struct drm_device *drm_dev, + struct drm_file *file, + struct drm_exynos_ipp_cmd_node *c_node, + struct drm_exynos_ipp_queue_buf *qbuf) +{ + struct drm_exynos_ipp_send_event *e; + unsigned long flags; + + DRM_DEBUG_KMS("%s:ops_id[%d]buf_id[%d]\n", __func__, + qbuf->ops_id, qbuf->buf_id); + + e = kzalloc(sizeof(*e), GFP_KERNEL); + if (!e) { + spin_lock_irqsave(&drm_dev->event_lock, flags); + file->event_space += sizeof(e->event); + spin_unlock_irqrestore(&drm_dev->event_lock, flags); + return -ENOMEM; + } + + /* make event */ + e->event.base.type = DRM_EXYNOS_IPP_EVENT; + e->event.base.length = sizeof(e->event); + e->event.user_data = qbuf->user_data; + e->event.prop_id = qbuf->prop_id; + e->event.buf_id[EXYNOS_DRM_OPS_DST] = qbuf->buf_id; + e->base.event = &e->event.base; + e->base.file_priv = file; + e->base.destroy = ipp_free_event; + list_add_tail(&e->base.link, &c_node->event_list); + + return 0; +} + +static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, + struct drm_exynos_ipp_queue_buf *qbuf) +{ + struct drm_exynos_ipp_send_event *e, *te; + int count = 0; + + if (list_empty(&c_node->event_list)) { + DRM_DEBUG_KMS("%s:event_list is empty.\n", __func__); + return; + } + + list_for_each_entry_safe(e, te, &c_node->event_list, base.link) { + DRM_DEBUG_KMS("%s:count[%d]e[0x%x]\n", + __func__, count++, (int)e); + + /* + * quf == NULL condition means all event deletion. + * stop operations want to delete all event list. + * another case delete only same buf id. + */ + if (!qbuf) { + /* delete list */ + list_del(&e->base.link); + kfree(e); + } + + /* compare buffer id */ + if (qbuf && (qbuf->buf_id == + e->event.buf_id[EXYNOS_DRM_OPS_DST])) { + /* delete list */ + list_del(&e->base.link); + kfree(e); + return; + } + } +} + static void ipp_clean_cmd_node(struct drm_device *drm_dev, struct drm_exynos_ipp_cmd_node *c_node) { @@ -678,6 +753,9 @@ static void ipp_clean_cmd_node(struct drm_device *drm_dev, cancel_work_sync(&c_node->stop_work->work); cancel_work_sync(&c_node->event_work->work); + /* put event */ + ipp_put_event(c_node, NULL); + for_each_ipp_ops(i) ipp_clean_mem_nodes(drm_dev, c_node, i); @@ -811,81 +889,6 @@ err_unlock: return ret; } -static void ipp_free_event(struct drm_pending_event *event) -{ - kfree(event); -} - -static int ipp_get_event(struct drm_device *drm_dev, - struct drm_file *file, - struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_send_event *e; - unsigned long flags; - - DRM_DEBUG_KMS("%s:ops_id[%d]buf_id[%d]\n", __func__, - qbuf->ops_id, qbuf->buf_id); - - e = kzalloc(sizeof(*e), GFP_KERNEL); - if (!e) { - spin_lock_irqsave(&drm_dev->event_lock, flags); - file->event_space += sizeof(e->event); - spin_unlock_irqrestore(&drm_dev->event_lock, flags); - return -ENOMEM; - } - - /* make event */ - e->event.base.type = DRM_EXYNOS_IPP_EVENT; - e->event.base.length = sizeof(e->event); - e->event.user_data = qbuf->user_data; - e->event.prop_id = qbuf->prop_id; - e->event.buf_id[EXYNOS_DRM_OPS_DST] = qbuf->buf_id; - e->base.event = &e->event.base; - e->base.file_priv = file; - e->base.destroy = ipp_free_event; - list_add_tail(&e->base.link, &c_node->event_list); - - return 0; -} - -static void ipp_put_event(struct drm_exynos_ipp_cmd_node *c_node, - struct drm_exynos_ipp_queue_buf *qbuf) -{ - struct drm_exynos_ipp_send_event *e, *te; - int count = 0; - - if (list_empty(&c_node->event_list)) { - DRM_DEBUG_KMS("%s:event_list is empty.\n", __func__); - return; - } - - list_for_each_entry_safe(e, te, &c_node->event_list, base.link) { - DRM_DEBUG_KMS("%s:count[%d]e[0x%x]\n", - __func__, count++, (int)e); - - /* - * quf == NULL condition means all event deletion. - * stop operations want to delete all event list. - * another case delete only same buf id. - */ - if (!qbuf) { - /* delete list */ - list_del(&e->base.link); - kfree(e); - } - - /* compare buffer id */ - if (qbuf && (qbuf->buf_id == - e->event.buf_id[EXYNOS_DRM_OPS_DST])) { - /* delete list */ - list_del(&e->base.link); - kfree(e); - return; - } - } -} - static void ipp_handle_cmd_work(struct device *dev, struct exynos_drm_ippdrv *ippdrv, struct drm_exynos_ipp_cmd_work *cmd_work, @@ -1391,9 +1394,6 @@ static int ipp_stop_property(struct drm_device *drm_dev, DRM_DEBUG_KMS("%s:prop_id[%d]\n", __func__, property->prop_id); - /* put event */ - ipp_put_event(c_node, NULL); - /* stop operations */ if (ippdrv->stop) ippdrv->stop(ippdrv->dev, property->cmd); |