aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
diff options
context:
space:
mode:
authorLucas Stach <l.stach@pengutronix.de>2017-12-04 18:41:58 +0100
committerLucas Stach <l.stach@pengutronix.de>2018-02-12 16:30:59 +0100
commite93b6deeb45a781489f4ceaa97f9545a3cbebb81 (patch)
tree82b760c0285f254b0fa73999f9da3230cdad2266 /drivers/gpu/drm/etnaviv/etnaviv_gpu.c
parentdrm/etnaviv: track fences by IDR instead of seqno (diff)
downloadlinux-dev-e93b6deeb45a781489f4ceaa97f9545a3cbebb81.tar.xz
linux-dev-e93b6deeb45a781489f4ceaa97f9545a3cbebb81.zip
drm/etnaviv: hook up DRM GPU scheduler
This hooks in the DRM GPU scheduler. No improvement yet, as all the dependency handling is still done in etnaviv_gem_submit. This just replaces the actual GPU submit by passing through the scheduler. Allows to get rid of the retire worker, as this is now driven by the scheduler. Signed-off-by: Lucas Stach <l.stach@pengutronix.de>
Diffstat (limited to 'drivers/gpu/drm/etnaviv/etnaviv_gpu.c')
-rw-r--r--drivers/gpu/drm/etnaviv/etnaviv_gpu.c113
1 files changed, 39 insertions, 74 deletions
diff --git a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
index bab6a8286520..fa5063010435 100644
--- a/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
+++ b/drivers/gpu/drm/etnaviv/etnaviv_gpu.c
@@ -26,6 +26,7 @@
#include "etnaviv_gem.h"
#include "etnaviv_mmu.h"
#include "etnaviv_perfmon.h"
+#include "etnaviv_sched.h"
#include "common.xml.h"
#include "state.xml.h"
#include "state_hi.xml.h"
@@ -961,9 +962,6 @@ static void recover_worker(struct work_struct *work)
mutex_unlock(&gpu->lock);
pm_runtime_mark_last_busy(gpu->dev);
pm_runtime_put_autosuspend(gpu->dev);
-
- /* Retire the buffer objects in a work */
- queue_work(gpu->wq, &gpu->retire_work);
}
static void hangcheck_timer_reset(struct etnaviv_gpu *gpu)
@@ -1016,7 +1014,6 @@ static void hangcheck_disable(struct etnaviv_gpu *gpu)
/* fence object management */
struct etnaviv_fence {
struct etnaviv_gpu *gpu;
- int id;
struct dma_fence base;
};
@@ -1053,11 +1050,6 @@ static void etnaviv_fence_release(struct dma_fence *fence)
{
struct etnaviv_fence *f = to_etnaviv_fence(fence);
- /* first remove from IDR, so fence can not be looked up anymore */
- mutex_lock(&f->gpu->lock);
- idr_remove(&f->gpu->fence_idr, f->id);
- mutex_unlock(&f->gpu->lock);
-
kfree_rcu(f, base.rcu);
}
@@ -1084,11 +1076,6 @@ static struct dma_fence *etnaviv_gpu_fence_alloc(struct etnaviv_gpu *gpu)
if (!f)
return NULL;
- f->id = idr_alloc_cyclic(&gpu->fence_idr, &f->base, 0, INT_MAX, GFP_KERNEL);
- if (f->id < 0) {
- kfree(f);
- return NULL;
- }
f->gpu = gpu;
dma_fence_init(&f->base, &etnaviv_fence_ops, &gpu->fence_spinlock,
@@ -1211,31 +1198,6 @@ static void event_free(struct etnaviv_gpu *gpu, unsigned int event)
/*
* Cmdstream submission/retirement:
*/
-
-static void retire_worker(struct work_struct *work)
-{
- struct etnaviv_gpu *gpu = container_of(work, struct etnaviv_gpu,
- retire_work);
- u32 fence = gpu->completed_fence;
- struct etnaviv_gem_submit *submit, *tmp;
- LIST_HEAD(retire_list);
-
- mutex_lock(&gpu->lock);
- list_for_each_entry_safe(submit, tmp, &gpu->active_submit_list, node) {
- if (!dma_fence_is_signaled(submit->out_fence))
- break;
-
- list_move(&submit->node, &retire_list);
- }
-
- gpu->retired_fence = fence;
-
- mutex_unlock(&gpu->lock);
-
- list_for_each_entry_safe(submit, tmp, &retire_list, node)
- etnaviv_submit_put(submit);
-}
-
int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
u32 id, struct timespec *timeout)
{
@@ -1243,18 +1205,15 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
int ret;
/*
- * Look up the fence and take a reference. The mutex only synchronizes
- * the IDR lookup with the fence release. We might still find a fence
+ * Look up the fence and take a reference. We might still find a fence
* whose refcount has already dropped to zero. dma_fence_get_rcu
* pretends we didn't find a fence in that case.
*/
- ret = mutex_lock_interruptible(&gpu->lock);
- if (ret)
- return ret;
+ rcu_read_lock();
fence = idr_find(&gpu->fence_idr, id);
if (fence)
fence = dma_fence_get_rcu(fence);
- mutex_unlock(&gpu->lock);
+ rcu_read_unlock();
if (!fence)
return 0;
@@ -1279,7 +1238,7 @@ int etnaviv_gpu_wait_fence_interruptible(struct etnaviv_gpu *gpu,
/*
* Wait for an object to become inactive. This, on it's own, is not race
- * free: the object is moved by the retire worker off the active list, and
+ * free: the object is moved by the scheduler off the active list, and
* then the iova is put. Moreover, the object could be re-submitted just
* after we notice that it's become inactive.
*
@@ -1368,15 +1327,16 @@ static void sync_point_perfmon_sample_post(struct etnaviv_gpu *gpu,
/* add bo's to gpu's ring, and kick gpu: */
-int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
- struct etnaviv_gem_submit *submit)
+struct dma_fence *etnaviv_gpu_submit(struct etnaviv_gem_submit *submit)
{
+ struct etnaviv_gpu *gpu = submit->gpu;
+ struct dma_fence *gpu_fence;
unsigned int i, nr_events = 1, event[3];
int ret;
ret = pm_runtime_get_sync(gpu->dev);
if (ret < 0)
- return ret;
+ return NULL;
submit->runtime_resumed = true;
/*
@@ -1392,22 +1352,20 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
ret = event_alloc(gpu, nr_events, event);
if (ret) {
DRM_ERROR("no free events\n");
- return ret;
+ return NULL;
}
mutex_lock(&gpu->lock);
- submit->out_fence = etnaviv_gpu_fence_alloc(gpu);
- if (!submit->out_fence) {
+ gpu_fence = etnaviv_gpu_fence_alloc(gpu);
+ if (!gpu_fence) {
for (i = 0; i < nr_events; i++)
event_free(gpu, event[i]);
- ret = -ENOMEM;
goto out_unlock;
}
- submit->out_fence_id = to_etnaviv_fence(submit->out_fence)->id;
- gpu->active_fence = submit->out_fence->seqno;
+ gpu->active_fence = gpu_fence->seqno;
if (submit->nr_pmrs) {
gpu->event[event[1]].sync_point = &sync_point_perfmon_sample_pre;
@@ -1416,8 +1374,7 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
etnaviv_sync_point_queue(gpu, event[1]);
}
- kref_get(&submit->refcount);
- gpu->event[event[0]].fence = submit->out_fence;
+ gpu->event[event[0]].fence = gpu_fence;
etnaviv_buffer_queue(gpu, submit->exec_state, event[0],
&submit->cmdbuf);
@@ -1428,15 +1385,12 @@ int etnaviv_gpu_submit(struct etnaviv_gpu *gpu,
etnaviv_sync_point_queue(gpu, event[2]);
}
- list_add_tail(&submit->node, &gpu->active_submit_list);
-
hangcheck_timer_reset(gpu);
- ret = 0;
out_unlock:
mutex_unlock(&gpu->lock);
- return ret;
+ return gpu_fence;
}
static void sync_point_worker(struct work_struct *work)
@@ -1527,9 +1481,6 @@ static irqreturn_t irq_handler(int irq, void *data)
event_free(gpu, event);
}
- /* Retire the buffer objects in a work */
- queue_work(gpu->wq, &gpu->retire_work);
-
ret = IRQ_HANDLED;
}
@@ -1701,22 +1652,22 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
gpu->wq = alloc_ordered_workqueue(dev_name(dev), 0);
if (!gpu->wq) {
- if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL))
- thermal_cooling_device_unregister(gpu->cooling);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto out_thermal;
}
+ ret = etnaviv_sched_init(gpu);
+ if (ret)
+ goto out_workqueue;
+
#ifdef CONFIG_PM
ret = pm_runtime_get_sync(gpu->dev);
#else
ret = etnaviv_gpu_clk_enable(gpu);
#endif
- if (ret < 0) {
- destroy_workqueue(gpu->wq);
- if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL))
- thermal_cooling_device_unregister(gpu->cooling);
- return ret;
- }
+ if (ret < 0)
+ goto out_sched;
+
gpu->drm = drm;
gpu->fence_context = dma_fence_context_alloc(1);
@@ -1724,7 +1675,6 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
spin_lock_init(&gpu->fence_spinlock);
INIT_LIST_HEAD(&gpu->active_submit_list);
- INIT_WORK(&gpu->retire_work, retire_worker);
INIT_WORK(&gpu->sync_point_work, sync_point_worker);
INIT_WORK(&gpu->recover_work, recover_worker);
init_waitqueue_head(&gpu->fence_event);
@@ -1737,6 +1687,18 @@ static int etnaviv_gpu_bind(struct device *dev, struct device *master,
pm_runtime_put_autosuspend(gpu->dev);
return 0;
+
+out_sched:
+ etnaviv_sched_fini(gpu);
+
+out_workqueue:
+ destroy_workqueue(gpu->wq);
+
+out_thermal:
+ if (IS_ENABLED(CONFIG_DRM_ETNAVIV_THERMAL))
+ thermal_cooling_device_unregister(gpu->cooling);
+
+ return ret;
}
static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
@@ -1751,6 +1713,8 @@ static void etnaviv_gpu_unbind(struct device *dev, struct device *master,
flush_workqueue(gpu->wq);
destroy_workqueue(gpu->wq);
+ etnaviv_sched_fini(gpu);
+
#ifdef CONFIG_PM
pm_runtime_get_sync(gpu->dev);
pm_runtime_put_sync_suspend(gpu->dev);
@@ -1803,6 +1767,7 @@ static int etnaviv_gpu_platform_probe(struct platform_device *pdev)
gpu->dev = &pdev->dev;
mutex_init(&gpu->lock);
+ mutex_init(&gpu->fence_idr_lock);
/* Map registers: */
gpu->mmio = etnaviv_ioremap(pdev, NULL, dev_name(gpu->dev));