summaryrefslogtreecommitdiff
path: root/drivers/gpu/drm/exynos/exynos_drm_ipp.c
diff options
context:
space:
mode:
authorAndrzej Hajda <a.hajda@samsung.com>2014-08-28 13:07:35 +0400
committerInki Dae <daeinki@gmail.com>2014-09-19 19:56:12 +0400
commitc0592c854959214a2b08eeb776afae5dfe5dc053 (patch)
treeb2e51e7f8b7fc3cc3af0bb4b9a4594344fe6e9f4 /drivers/gpu/drm/exynos/exynos_drm_ipp.c
parent8aa99dd3762b67e6555a9f3ef015989bbace39a5 (diff)
downloadlinux-c0592c854959214a2b08eeb776afae5dfe5dc053.tar.xz
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. 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/exynos/exynos_drm_ipp.c')
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_ipp.c155
1 files changed, 78 insertions, 77 deletions
diff --git a/drivers/gpu/drm/exynos/exynos_drm_ipp.c b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
index 341db52e3939..05f0f4eae7bc 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_ipp.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_ipp.c
@@ -600,6 +600,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("ops_id[%d]buf_id[%d]\n", 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;
+ mutex_lock(&c_node->event_lock);
+ list_add_tail(&e->base.link, &c_node->event_list);
+ mutex_unlock(&c_node->event_lock);
+
+ 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;
+
+ 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);
+
+ /*
+ * qbuf == 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);
+ goto out_unlock;
+ }
+ }
+
+out_unlock:
+ mutex_unlock(&c_node->event_lock);
+ return;
+}
+
static void ipp_clean_cmd_node(struct ipp_context *ctx,
struct drm_exynos_ipp_cmd_node *c_node)
{
@@ -610,6 +685,9 @@ static void ipp_clean_cmd_node(struct ipp_context *ctx,
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(ctx->subdrv.drm_dev, c_node, i);
@@ -706,81 +784,6 @@ static int ipp_set_mem_node(struct exynos_drm_ippdrv *ippdrv,
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("ops_id[%d]buf_id[%d]\n", 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;
- mutex_lock(&c_node->event_lock);
- list_add_tail(&e->base.link, &c_node->event_list);
- mutex_unlock(&c_node->event_lock);
-
- 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;
-
- 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);
-
- /*
- * qbuf == 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);
- goto out_unlock;
- }
- }
-
-out_unlock:
- mutex_unlock(&c_node->event_lock);
- return;
-}
-
static void ipp_handle_cmd_work(struct device *dev,
struct exynos_drm_ippdrv *ippdrv,
struct drm_exynos_ipp_cmd_work *cmd_work,
@@ -1286,8 +1289,6 @@ static int ipp_stop_property(struct drm_device *drm_dev,
DRM_DEBUG_KMS("prop_id[%d]\n", property->prop_id);
- /* put event */
- ipp_put_event(c_node, NULL);
/* stop operations */
if (ippdrv->stop)
ippdrv->stop(ippdrv->dev, property->cmd);