#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"
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;
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);
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)
list_add(&task->node, &g2d_dev->tasks_free);
}
+ max_queued = G2D_MAX_JOBS;
+
return 0;
}