[RAMEN9610-10376] g2d: add blocking interface by module param
authorhyesoo.yu <hyesoo.yu@samsung.com>
Mon, 24 Dec 2018 06:32:06 +0000 (15:32 +0900)
committerhskang <hs1218.kang@samsung.com>
Fri, 4 Jan 2019 07:16:17 +0000 (16:16 +0900)
If the jobs are queued larger than max_queued set by
module param or there is not free task on list,
the user request of task could be returned with -EBUSY
immediately, or wait until the number of queued job
is less than max_queued and free list is not empty.

Change-Id: I71dde2620830ea7e4426c86d70b7cd8eba9af952
Signed-off-by: hyesoo.yu <hyesoo.yu@samsung.com>
drivers/gpu/exynos/g2d/g2d.h
drivers/gpu/exynos/g2d/g2d_debug.c
drivers/gpu/exynos/g2d/g2d_debug.h
drivers/gpu/exynos/g2d/g2d_drv.c
drivers/gpu/exynos/g2d/g2d_task.c

index 81aae54c984d66ca3020b030ce9ef482a6e809c7..d76f219791186d49ebf2a468fca881e79d1a9416 100644 (file)
@@ -104,6 +104,7 @@ struct g2d_device {
 
        struct notifier_block   pm_notifier;
        wait_queue_head_t       freeze_wait;
+       wait_queue_head_t       queued_wait;
 
        struct dentry *debug_root;
        struct dentry *debug;
index 9e931ff2420b7db63946aabd22a6dce764537835..87106d5112eb124f0630d212a6a3a01fa5a0d89f 100644 (file)
@@ -69,6 +69,7 @@ static struct g2d_stamp_type {
        {"suspend",       G2D_STAMPTYPE_INOUT,     false},
        {"resume",        G2D_STAMPTYPE_INOUT,     false},
        {"hwfc_job",      G2D_STAMPTYPE_NUM,       true},
+       {"pending",       G2D_STAMPTYPE_NUM,       false},
 };
 
 static bool g2d_stamp_show_single(struct seq_file *s, struct g2d_stamp *stamp)
index ae511d0006d5f8fd80b5a43b3c9656a34eaffa9b..cd1a9ab491d9521e3ba16479af807e4b691874d0 100644 (file)
@@ -39,6 +39,7 @@ enum g2d_stamp_id {
        G2D_STAMP_STATE_SUSPEND,
        G2D_STAMP_STATE_RESUME,
        G2D_STAMP_STATE_HWFCBUF,
+       G2D_STAMP_STATE_PENDING,
        G2D_STAMP_STATE_NUM,
 };
 
index d5ec2a07b928881c8a5ae4f09a33f35f79c7e5bd..5ce4388280ba45e88d52c95b32652adc18a5af91 100644 (file)
@@ -920,6 +920,7 @@ static int g2d_probe(struct platform_device *pdev)
        }
 
        init_waitqueue_head(&g2d_dev->freeze_wait);
+       init_waitqueue_head(&g2d_dev->queued_wait);
 
        g2d_dev->pm_notifier.notifier_call = &g2d_notifier_event;
        ret = register_pm_notifier(&g2d_dev->pm_notifier);
index 80d6bf3d38f7d0ceac7c372de8d48e6ef2b4c2c1..83dfe6cd9d7ed4acd2d5887d7526d5507e74258b 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/slab.h>
 #include <linux/pm_runtime.h>
 #include <linux/exynos_iovmm.h>
+#include <linux/module.h>
 
 #include "g2d.h"
 #include "g2d_task.h"
@@ -320,12 +321,34 @@ void g2d_fence_callback(struct dma_fence *fence, struct dma_fence_cb *cb)
        spin_unlock_irqrestore(&layer->task->fence_timeout_lock, flags);
 }
 
+static bool block_on_contension;
+module_param(block_on_contension, bool, 0644);
+
+static int max_queued;
+module_param(max_queued, int, 0644);
+
+static int g2d_queued_task_count(struct g2d_device *g2d_dev)
+{
+       struct g2d_task *task;
+       int num_queued = 0;
+
+       list_for_each_entry(task, &g2d_dev->tasks_active, node)
+               num_queued++;
+
+       list_for_each_entry(task, &g2d_dev->tasks_prepared, node)
+               num_queued++;
+
+       return num_queued;
+}
+
 struct g2d_task *g2d_get_free_task(struct g2d_device *g2d_dev,
                                    struct g2d_context *g2d_ctx, bool hwfc)
 {
        struct g2d_task *task;
        struct list_head *taskfree;
        unsigned long flags;
+       int num_queued = 0;
+       ktime_t ktime_pending;
 
        if (hwfc)
                taskfree = &g2d_dev->tasks_free_hwfc;
@@ -334,11 +357,34 @@ struct g2d_task *g2d_get_free_task(struct g2d_device *g2d_dev,
 
        spin_lock_irqsave(&g2d_dev->lock_task, flags);
 
-       if (list_empty(taskfree)) {
-               dev_err(g2d_dev->dev, "%s: no free task slot found(hwfc? %d)\n",
-                       __func__, hwfc);
+       while (list_empty(taskfree) ||
+              ((num_queued = g2d_queued_task_count(g2d_dev)) >= max_queued)) {
+
                spin_unlock_irqrestore(&g2d_dev->lock_task, flags);
-               return NULL;
+
+               if (list_empty(taskfree))
+                       dev_err(g2d_dev->dev,
+                               "%s : no free task slot found (hwfc %d)",
+                               __func__, hwfc);
+               else
+                       dev_err(g2d_dev->dev, "%s : queued %d >= max %d",
+                               __func__, num_queued, max_queued);
+
+               if (!block_on_contension)
+                       return NULL;
+
+               ktime_pending = ktime_get();
+
+               g2d_stamp_task(NULL, G2D_STAMP_STATE_PENDING, num_queued);
+               wait_event(g2d_dev->queued_wait,
+                          !list_empty(taskfree) &&
+                          (g2d_queued_task_count(g2d_dev) < max_queued));
+
+               dev_err(g2d_dev->dev,
+                       "%s : wait to resolve contension for %d us", __func__,
+                       (int)ktime_us_delta(ktime_get(), ktime_pending));
+
+               spin_lock_irqsave(&g2d_dev->lock_task, flags);
        }
 
        task = list_first_entry(taskfree, struct g2d_task, node);
@@ -378,6 +424,8 @@ void g2d_put_free_task(struct g2d_device *g2d_dev, struct g2d_task *task)
        g2d_stamp_task(task, G2D_STAMP_STATE_TASK_RESOURCE, 1);
 
        spin_unlock_irqrestore(&g2d_dev->lock_task, flags);
+
+       wake_up(&g2d_dev->queued_wait);
 }
 
 void g2d_destroy_tasks(struct g2d_device *g2d_dev)
@@ -491,5 +539,7 @@ int g2d_create_tasks(struct g2d_device *g2d_dev)
                        list_add(&task->node, &g2d_dev->tasks_free);
        }
 
+       max_queued = G2D_MAX_JOBS;
+
        return 0;
 }