Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 73cb9701 authored by Chris Wilson's avatar Chris Wilson
Browse files

drm/i915: Combine seqno + tracking into a global timeline struct



Our timelines are more than just a seqno. They also provide an ordered
list of requests to be executed. Due to the restriction of handling
individual address spaces, we are limited to a timeline per address
space but we use a fence context per engine within.

Our first step to introducing independent timelines per context (i.e. to
allow each context to have a queue of requests to execute that have a
defined set of dependencies on other requests) is to provide a timeline
abstraction for the global execution queue.

Signed-off-by: default avatarChris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161028125858.23563-23-chris@chris-wilson.co.uk
parent c004a90b
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ i915-y += i915_cmd_parser.o \
	  i915_gem_shrinker.o \
	  i915_gem_stolen.o \
	  i915_gem_tiling.o \
	  i915_gem_timeline.o \
	  i915_gem_userptr.o \
	  i915_trace_points.o \
	  intel_breadcrumbs.o \
+13 −20
Original line number Diff line number Diff line
@@ -552,7 +552,7 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
				seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
					   engine->name,
					   i915_gem_request_get_seqno(work->flip_queued_req),
					   dev_priv->next_seqno,
					   dev_priv->gt.global_timeline.next_seqno,
					   intel_engine_get_seqno(engine),
					   i915_gem_request_completed(work->flip_queued_req));
			} else
@@ -662,13 +662,13 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
		int count;

		count = 0;
		list_for_each_entry(req, &engine->request_list, link)
		list_for_each_entry(req, &engine->timeline->requests, link)
			count++;
		if (count == 0)
			continue;

		seq_printf(m, "%s requests: %d\n", engine->name, count);
		list_for_each_entry(req, &engine->request_list, link)
		list_for_each_entry(req, &engine->timeline->requests, link)
			print_request(m, req, "    ");

		any++;
@@ -1052,15 +1052,8 @@ static int
i915_next_seqno_get(void *data, u64 *val)
{
	struct drm_i915_private *dev_priv = data;
	int ret;

	ret = mutex_lock_interruptible(&dev_priv->drm.struct_mutex);
	if (ret)
		return ret;

	*val = dev_priv->next_seqno;
	mutex_unlock(&dev_priv->drm.struct_mutex);

	*val = READ_ONCE(dev_priv->gt.global_timeline.next_seqno);
	return 0;
}

@@ -1075,7 +1068,7 @@ i915_next_seqno_set(void *data, u64 val)
	if (ret)
		return ret;

	ret = i915_gem_set_seqno(dev, val);
	ret = i915_gem_set_global_seqno(dev, val);
	mutex_unlock(&dev->struct_mutex);

	return ret;
@@ -1364,7 +1357,7 @@ static int i915_hangcheck_info(struct seq_file *m, void *unused)
		seq_printf(m, "\tseqno = %x [current %x, last %x]\n",
			   engine->hangcheck.seqno,
			   seqno[id],
			   engine->last_submitted_seqno);
			   engine->timeline->last_submitted_seqno);
		seq_printf(m, "\twaiters? %s, fake irq active? %s\n",
			   yesno(intel_engine_has_waiter(engine)),
			   yesno(test_bit(engine->id,
@@ -3181,7 +3174,7 @@ static int i915_engine_info(struct seq_file *m, void *unused)
		seq_printf(m, "%s\n", engine->name);
		seq_printf(m, "\tcurrent seqno %x, last %x, hangcheck %x [score %d]\n",
			   intel_engine_get_seqno(engine),
			   engine->last_submitted_seqno,
			   engine->timeline->last_submitted_seqno,
			   engine->hangcheck.seqno,
			   engine->hangcheck.score);

@@ -3189,14 +3182,14 @@ static int i915_engine_info(struct seq_file *m, void *unused)

		seq_printf(m, "\tRequests:\n");

		rq = list_first_entry(&engine->request_list,
		rq = list_first_entry(&engine->timeline->requests,
				      struct drm_i915_gem_request, link);
		if (&rq->link != &engine->request_list)
		if (&rq->link != &engine->timeline->requests)
			print_request(m, rq, "\t\tfirst  ");

		rq = list_last_entry(&engine->request_list,
		rq = list_last_entry(&engine->timeline->requests,
				     struct drm_i915_gem_request, link);
		if (&rq->link != &engine->request_list)
		if (&rq->link != &engine->timeline->requests)
			print_request(m, rq, "\t\tlast   ");

		rq = i915_gem_find_active_request(engine);
+5 −1
Original line number Diff line number Diff line
@@ -831,7 +831,9 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
	intel_init_display_hooks(dev_priv);
	intel_init_clock_gating_hooks(dev_priv);
	intel_init_audio_hooks(dev_priv);
	i915_gem_load_init(&dev_priv->drm);
	ret = i915_gem_load_init(&dev_priv->drm);
	if (ret < 0)
		goto err_gvt;

	intel_display_crc_init(dev_priv);

@@ -841,6 +843,8 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,

	return 0;

err_gvt:
	intel_gvt_cleanup(dev_priv);
err_workqueues:
	i915_workqueues_cleanup(dev_priv);
	return ret;
+6 −3
Original line number Diff line number Diff line
@@ -63,6 +63,7 @@
#include "i915_gem_gtt.h"
#include "i915_gem_render_state.h"
#include "i915_gem_request.h"
#include "i915_gem_timeline.h"

#include "intel_gvt.h"

@@ -1830,7 +1831,6 @@ struct drm_i915_private {
	struct i915_gem_context *kernel_context;
	struct intel_engine_cs *engine[I915_NUM_ENGINES];
	struct i915_vma *semaphore;
	u32 next_seqno;

	struct drm_dma_handle *status_page_dmah;
	struct resource mch_res;
@@ -2090,6 +2090,9 @@ struct drm_i915_private {
		void (*resume)(struct drm_i915_private *);
		void (*cleanup_engine)(struct intel_engine_cs *engine);

		struct list_head timelines;
		struct i915_gem_timeline global_timeline;

		/**
		 * Is the GPU currently considered idle, or busy executing
		 * userspace requests? Whilst idle, we allow runtime power
@@ -3175,7 +3178,7 @@ int i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
				struct drm_file *file_priv);
int i915_gem_wait_ioctl(struct drm_device *dev, void *data,
			struct drm_file *file_priv);
void i915_gem_load_init(struct drm_device *dev);
int i915_gem_load_init(struct drm_device *dev);
void i915_gem_load_cleanup(struct drm_device *dev);
void i915_gem_load_init_fences(struct drm_i915_private *dev_priv);
int i915_gem_freeze(struct drm_i915_private *dev_priv);
@@ -3347,7 +3350,7 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
		       struct drm_i915_gem_object *new,
		       unsigned frontbuffer_bits);

int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno);
int __must_check i915_gem_set_global_seqno(struct drm_device *dev, u32 seqno);

struct drm_i915_gem_request *
i915_gem_find_active_request(struct intel_engine_cs *engine);
+58 −14
Original line number Diff line number Diff line
@@ -371,7 +371,7 @@ i915_gem_object_wait_fence(struct dma_fence *fence,
	if (flags & I915_WAIT_LOCKED && i915_gem_request_completed(rq))
		i915_gem_request_retire_upto(rq);

	if (rps && rq->fence.seqno == rq->engine->last_submitted_seqno) {
	if (rps && rq->fence.seqno == rq->timeline->last_submitted_seqno) {
		/* The GPU is now idle and this client has stalled.
		 * Since no other client has submitted a request in the
		 * meantime, assume that this client is the only one
@@ -2563,7 +2563,7 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
	 * extra delay for a recent interrupt is pointless. Hence, we do
	 * not need an engine->irq_seqno_barrier() before the seqno reads.
	 */
	list_for_each_entry(request, &engine->request_list, link) {
	list_for_each_entry(request, &engine->timeline->requests, link) {
		if (i915_gem_request_completed(request))
			continue;

@@ -2632,7 +2632,7 @@ static void i915_gem_reset_engine(struct intel_engine_cs *engine)
	if (i915_gem_context_is_default(incomplete_ctx))
		return;

	list_for_each_entry_continue(request, &engine->request_list, link)
	list_for_each_entry_continue(request, &engine->timeline->requests, link)
		if (request->ctx == incomplete_ctx)
			reset_request(request);
}
@@ -2671,7 +2671,8 @@ static void i915_gem_cleanup_engine(struct intel_engine_cs *engine)
	 * (lockless) lookup doesn't try and wait upon the request as we
	 * reset it.
	 */
	intel_engine_init_seqno(engine, engine->last_submitted_seqno);
	intel_engine_init_global_seqno(engine,
				       engine->timeline->last_submitted_seqno);

	/*
	 * Clear the execlists queue up before freeing the requests, as those
@@ -2979,18 +2980,26 @@ int i915_vma_unbind(struct i915_vma *vma)
	return 0;
}

int i915_gem_wait_for_idle(struct drm_i915_private *dev_priv,
			   unsigned int flags)
static int wait_for_timeline(struct i915_gem_timeline *tl, unsigned int flags)
{
	struct intel_engine_cs *engine;
	enum intel_engine_id id;
	int ret;
	int ret, i;

	for_each_engine(engine, dev_priv, id) {
		if (engine->last_context == NULL)
			continue;
	for (i = 0; i < ARRAY_SIZE(tl->engine); i++) {
		ret = i915_gem_active_wait(&tl->engine[i].last_request, flags);
		if (ret)
			return ret;
	}

		ret = intel_engine_idle(engine, flags);
	return 0;
}

int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
{
	struct i915_gem_timeline *tl;
	int ret;

	list_for_each_entry(tl, &i915->gt.timelines, link) {
		ret = wait_for_timeline(tl, flags);
		if (ret)
			return ret;
	}
@@ -4680,21 +4689,32 @@ i915_gem_load_init_fences(struct drm_i915_private *dev_priv)
	i915_gem_detect_bit_6_swizzle(dev);
}

void
int
i915_gem_load_init(struct drm_device *dev)
{
	struct drm_i915_private *dev_priv = to_i915(dev);
	int err;

	dev_priv->objects =
		kmem_cache_create("i915_gem_object",
				  sizeof(struct drm_i915_gem_object), 0,
				  SLAB_HWCACHE_ALIGN,
				  NULL);
	if (!dev_priv->objects) {
		err = -ENOMEM;
		goto err_out;
	}

	dev_priv->vmas =
		kmem_cache_create("i915_gem_vma",
				  sizeof(struct i915_vma), 0,
				  SLAB_HWCACHE_ALIGN,
				  NULL);
	if (!dev_priv->vmas) {
		err = -ENOMEM;
		goto err_objects;
	}

	dev_priv->requests =
		kmem_cache_create("i915_gem_request",
				  sizeof(struct drm_i915_gem_request), 0,
@@ -4702,6 +4722,19 @@ i915_gem_load_init(struct drm_device *dev)
				  SLAB_RECLAIM_ACCOUNT |
				  SLAB_DESTROY_BY_RCU,
				  NULL);
	if (!dev_priv->requests) {
		err = -ENOMEM;
		goto err_vmas;
	}

	mutex_lock(&dev_priv->drm.struct_mutex);
	INIT_LIST_HEAD(&dev_priv->gt.timelines);
	err = i915_gem_timeline_init(dev_priv,
				     &dev_priv->gt.global_timeline,
				     "[execution]");
	mutex_unlock(&dev_priv->drm.struct_mutex);
	if (err)
		goto err_requests;

	INIT_LIST_HEAD(&dev_priv->context_list);
	INIT_WORK(&dev_priv->mm.free_work, __i915_gem_free_work);
@@ -4726,6 +4759,17 @@ i915_gem_load_init(struct drm_device *dev)
	atomic_set(&dev_priv->mm.bsd_engine_dispatch_index, 0);

	spin_lock_init(&dev_priv->fb_tracking.lock);

	return 0;

err_requests:
	kmem_cache_destroy(dev_priv->requests);
err_vmas:
	kmem_cache_destroy(dev_priv->vmas);
err_objects:
	kmem_cache_destroy(dev_priv->objects);
err_out:
	return err;
}

void i915_gem_load_cleanup(struct drm_device *dev)
Loading