Skip to content

Commit

Permalink
drm/i915: Combine seqno + tracking into a global timeline struct
Browse files Browse the repository at this point in the history
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: Chris Wilson <chris@chris-wilson.co.uk>
Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com>
Link: http://patchwork.freedesktop.org/patch/msgid/20161028125858.23563-23-chris@chris-wilson.co.uk
  • Loading branch information
Chris Wilson committed Oct 28, 2016
1 parent c004a90 commit 73cb970
Show file tree
Hide file tree
Showing 15 changed files with 286 additions and 115 deletions.
1 change: 1 addition & 0 deletions drivers/gpu/drm/i915/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
33 changes: 13 additions & 20 deletions drivers/gpu/drm/i915/i915_debugfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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++;
Expand Down Expand Up @@ -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;
}

Expand All @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -3181,22 +3174,22 @@ 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);

rcu_read_lock();

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

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

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

rq = i915_gem_find_active_request(engine);
Expand Down
6 changes: 5 additions & 1 deletion drivers/gpu/drm/i915/i915_drv.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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;
Expand Down
9 changes: 6 additions & 3 deletions drivers/gpu/drm/i915/i915_drv.h
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
72 changes: 58 additions & 14 deletions drivers/gpu/drm/i915/i915_gem.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -4680,28 +4689,52 @@ 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,
SLAB_HWCACHE_ALIGN |
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);
Expand All @@ -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)
Expand Down
2 changes: 2 additions & 0 deletions drivers/gpu/drm/i915/i915_gem.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,6 @@
#define GEM_BUG_ON(expr)
#endif

#define I915_NUM_ENGINES 5

#endif /* __I915_GEM_H__ */
Loading

0 comments on commit 73cb970

Please sign in to comment.