Skip to content

Commit a89d1f9

Browse files
committed
drm/i915: Split i915_gem_timeline into individual timelines
We need to move to a more flexible timeline that doesn't assume one fence context per engine, and so allow for a single timeline to be used across a combination of engines. This means that preallocating a fence context per engine is now a hindrance, and so we want to introduce the singular timeline. From the code perspective, this has the notable advantage of clearing up a lot of mirky semantics and some clumsy pointer chasing. By splitting the timeline up into a single entity rather than an array of per-engine timelines, we can realise the goal of the previous patch of tracking the timeline alongside the ring. v2: Tweak wait_for_idle to stop the compiling thinking that ret may be uninitialised. Signed-off-by: Chris Wilson <[email protected]> Cc: Tvrtko Ursulin <[email protected]> Reviewed-by: Tvrtko Ursulin <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 65fcb80 commit a89d1f9

24 files changed

+397
-582
lines changed

drivers/gpu/drm/i915/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,11 @@ i915-y += i915_cmd_parser.o \
7171
i915_gem_shrinker.o \
7272
i915_gem_stolen.o \
7373
i915_gem_tiling.o \
74-
i915_gem_timeline.o \
7574
i915_gem_userptr.o \
7675
i915_gemfs.o \
7776
i915_query.o \
7877
i915_request.o \
78+
i915_timeline.o \
7979
i915_trace_points.o \
8080
i915_vma.o \
8181
intel_breadcrumbs.o \

drivers/gpu/drm/i915/i915_drv.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,10 @@
7272
#include "i915_gem_fence_reg.h"
7373
#include "i915_gem_object.h"
7474
#include "i915_gem_gtt.h"
75-
#include "i915_gem_timeline.h"
7675
#include "i915_gpu_error.h"
7776
#include "i915_request.h"
7877
#include "i915_scheduler.h"
78+
#include "i915_timeline.h"
7979
#include "i915_vma.h"
8080

8181
#include "intel_gvt.h"
@@ -2059,8 +2059,6 @@ struct drm_i915_private {
20592059
void (*resume)(struct drm_i915_private *);
20602060
void (*cleanup_engine)(struct intel_engine_cs *engine);
20612061

2062-
struct i915_gem_timeline execution_timeline;
2063-
struct i915_gem_timeline legacy_timeline;
20642062
struct list_head timelines;
20652063

20662064
struct list_head active_rings;

drivers/gpu/drm/i915/i915_gem.c

Lines changed: 56 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ static u32 __i915_gem_park(struct drm_i915_private *i915)
162162
synchronize_irq(i915->drm.irq);
163163

164164
intel_engines_park(i915);
165-
i915_gem_timelines_park(i915);
165+
i915_timelines_park(i915);
166166

167167
i915_pmu_gt_parked(i915);
168168

@@ -2977,8 +2977,8 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
29772977
* extra delay for a recent interrupt is pointless. Hence, we do
29782978
* not need an engine->irq_seqno_barrier() before the seqno reads.
29792979
*/
2980-
spin_lock_irqsave(&engine->timeline->lock, flags);
2981-
list_for_each_entry(request, &engine->timeline->requests, link) {
2980+
spin_lock_irqsave(&engine->timeline.lock, flags);
2981+
list_for_each_entry(request, &engine->timeline.requests, link) {
29822982
if (__i915_request_completed(request, request->global_seqno))
29832983
continue;
29842984

@@ -2989,7 +2989,7 @@ i915_gem_find_active_request(struct intel_engine_cs *engine)
29892989
active = request;
29902990
break;
29912991
}
2992-
spin_unlock_irqrestore(&engine->timeline->lock, flags);
2992+
spin_unlock_irqrestore(&engine->timeline.lock, flags);
29932993

29942994
return active;
29952995
}
@@ -3110,23 +3110,23 @@ static void engine_skip_context(struct i915_request *request)
31103110
{
31113111
struct intel_engine_cs *engine = request->engine;
31123112
struct i915_gem_context *hung_ctx = request->ctx;
3113-
struct intel_timeline *timeline = request->timeline;
3113+
struct i915_timeline *timeline = request->timeline;
31143114
unsigned long flags;
31153115

3116-
GEM_BUG_ON(timeline == engine->timeline);
3116+
GEM_BUG_ON(timeline == &engine->timeline);
31173117

3118-
spin_lock_irqsave(&engine->timeline->lock, flags);
3118+
spin_lock_irqsave(&engine->timeline.lock, flags);
31193119
spin_lock(&timeline->lock);
31203120

3121-
list_for_each_entry_continue(request, &engine->timeline->requests, link)
3121+
list_for_each_entry_continue(request, &engine->timeline.requests, link)
31223122
if (request->ctx == hung_ctx)
31233123
skip_request(request);
31243124

31253125
list_for_each_entry(request, &timeline->requests, link)
31263126
skip_request(request);
31273127

31283128
spin_unlock(&timeline->lock);
3129-
spin_unlock_irqrestore(&engine->timeline->lock, flags);
3129+
spin_unlock_irqrestore(&engine->timeline.lock, flags);
31303130
}
31313131

31323132
/* Returns the request if it was guilty of the hang */
@@ -3183,11 +3183,11 @@ i915_gem_reset_request(struct intel_engine_cs *engine,
31833183
dma_fence_set_error(&request->fence, -EAGAIN);
31843184

31853185
/* Rewind the engine to replay the incomplete rq */
3186-
spin_lock_irq(&engine->timeline->lock);
3186+
spin_lock_irq(&engine->timeline.lock);
31873187
request = list_prev_entry(request, link);
3188-
if (&request->link == &engine->timeline->requests)
3188+
if (&request->link == &engine->timeline.requests)
31893189
request = NULL;
3190-
spin_unlock_irq(&engine->timeline->lock);
3190+
spin_unlock_irq(&engine->timeline.lock);
31913191
}
31923192
}
31933193

@@ -3300,10 +3300,10 @@ static void nop_complete_submit_request(struct i915_request *request)
33003300
request->fence.context, request->fence.seqno);
33013301
dma_fence_set_error(&request->fence, -EIO);
33023302

3303-
spin_lock_irqsave(&request->engine->timeline->lock, flags);
3303+
spin_lock_irqsave(&request->engine->timeline.lock, flags);
33043304
__i915_request_submit(request);
33053305
intel_engine_init_global_seqno(request->engine, request->global_seqno);
3306-
spin_unlock_irqrestore(&request->engine->timeline->lock, flags);
3306+
spin_unlock_irqrestore(&request->engine->timeline.lock, flags);
33073307
}
33083308

33093309
void i915_gem_set_wedged(struct drm_i915_private *i915)
@@ -3372,10 +3372,10 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
33723372
* (lockless) lookup doesn't try and wait upon the request as we
33733373
* reset it.
33743374
*/
3375-
spin_lock_irqsave(&engine->timeline->lock, flags);
3375+
spin_lock_irqsave(&engine->timeline.lock, flags);
33763376
intel_engine_init_global_seqno(engine,
33773377
intel_engine_last_submit(engine));
3378-
spin_unlock_irqrestore(&engine->timeline->lock, flags);
3378+
spin_unlock_irqrestore(&engine->timeline.lock, flags);
33793379

33803380
i915_gem_reset_finish_engine(engine);
33813381
}
@@ -3387,8 +3387,7 @@ void i915_gem_set_wedged(struct drm_i915_private *i915)
33873387

33883388
bool i915_gem_unset_wedged(struct drm_i915_private *i915)
33893389
{
3390-
struct i915_gem_timeline *tl;
3391-
int i;
3390+
struct i915_timeline *tl;
33923391

33933392
lockdep_assert_held(&i915->drm.struct_mutex);
33943393
if (!test_bit(I915_WEDGED, &i915->gpu_error.flags))
@@ -3407,29 +3406,27 @@ bool i915_gem_unset_wedged(struct drm_i915_private *i915)
34073406
* No more can be submitted until we reset the wedged bit.
34083407
*/
34093408
list_for_each_entry(tl, &i915->gt.timelines, link) {
3410-
for (i = 0; i < ARRAY_SIZE(tl->engine); i++) {
3411-
struct i915_request *rq;
3409+
struct i915_request *rq;
34123410

3413-
rq = i915_gem_active_peek(&tl->engine[i].last_request,
3414-
&i915->drm.struct_mutex);
3415-
if (!rq)
3416-
continue;
3411+
rq = i915_gem_active_peek(&tl->last_request,
3412+
&i915->drm.struct_mutex);
3413+
if (!rq)
3414+
continue;
34173415

3418-
/*
3419-
* We can't use our normal waiter as we want to
3420-
* avoid recursively trying to handle the current
3421-
* reset. The basic dma_fence_default_wait() installs
3422-
* a callback for dma_fence_signal(), which is
3423-
* triggered by our nop handler (indirectly, the
3424-
* callback enables the signaler thread which is
3425-
* woken by the nop_submit_request() advancing the seqno
3426-
* and when the seqno passes the fence, the signaler
3427-
* then signals the fence waking us up).
3428-
*/
3429-
if (dma_fence_default_wait(&rq->fence, true,
3430-
MAX_SCHEDULE_TIMEOUT) < 0)
3431-
return false;
3432-
}
3416+
/*
3417+
* We can't use our normal waiter as we want to
3418+
* avoid recursively trying to handle the current
3419+
* reset. The basic dma_fence_default_wait() installs
3420+
* a callback for dma_fence_signal(), which is
3421+
* triggered by our nop handler (indirectly, the
3422+
* callback enables the signaler thread which is
3423+
* woken by the nop_submit_request() advancing the seqno
3424+
* and when the seqno passes the fence, the signaler
3425+
* then signals the fence waking us up).
3426+
*/
3427+
if (dma_fence_default_wait(&rq->fence, true,
3428+
MAX_SCHEDULE_TIMEOUT) < 0)
3429+
return false;
34333430
}
34343431
i915_retire_requests(i915);
34353432
GEM_BUG_ON(i915->gt.active_requests);
@@ -3734,17 +3731,9 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
37343731
return ret;
37353732
}
37363733

3737-
static int wait_for_timeline(struct i915_gem_timeline *tl, unsigned int flags)
3734+
static int wait_for_timeline(struct i915_timeline *tl, unsigned int flags)
37383735
{
3739-
int ret, i;
3740-
3741-
for (i = 0; i < ARRAY_SIZE(tl->engine); i++) {
3742-
ret = i915_gem_active_wait(&tl->engine[i].last_request, flags);
3743-
if (ret)
3744-
return ret;
3745-
}
3746-
3747-
return 0;
3736+
return i915_gem_active_wait(&tl->last_request, flags);
37483737
}
37493738

37503739
static int wait_for_engines(struct drm_i915_private *i915)
@@ -3762,30 +3751,37 @@ static int wait_for_engines(struct drm_i915_private *i915)
37623751

37633752
int i915_gem_wait_for_idle(struct drm_i915_private *i915, unsigned int flags)
37643753
{
3765-
int ret;
3766-
37673754
/* If the device is asleep, we have no requests outstanding */
37683755
if (!READ_ONCE(i915->gt.awake))
37693756
return 0;
37703757

37713758
if (flags & I915_WAIT_LOCKED) {
3772-
struct i915_gem_timeline *tl;
3759+
struct i915_timeline *tl;
3760+
int err;
37733761

37743762
lockdep_assert_held(&i915->drm.struct_mutex);
37753763

37763764
list_for_each_entry(tl, &i915->gt.timelines, link) {
3777-
ret = wait_for_timeline(tl, flags);
3778-
if (ret)
3779-
return ret;
3765+
err = wait_for_timeline(tl, flags);
3766+
if (err)
3767+
return err;
37803768
}
37813769
i915_retire_requests(i915);
37823770

3783-
ret = wait_for_engines(i915);
3771+
return wait_for_engines(i915);
37843772
} else {
3785-
ret = wait_for_timeline(&i915->gt.execution_timeline, flags);
3786-
}
3773+
struct intel_engine_cs *engine;
3774+
enum intel_engine_id id;
3775+
int err;
37873776

3788-
return ret;
3777+
for_each_engine(engine, i915, id) {
3778+
err = wait_for_timeline(&engine->timeline, flags);
3779+
if (err)
3780+
return err;
3781+
}
3782+
3783+
return 0;
3784+
}
37893785
}
37903786

37913787
static void __i915_gem_object_flush_for_display(struct drm_i915_gem_object *obj)
@@ -4954,7 +4950,7 @@ static void assert_kernel_context_is_current(struct drm_i915_private *i915)
49544950
enum intel_engine_id id;
49554951

49564952
for_each_engine(engine, i915, id) {
4957-
GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline->last_request));
4953+
GEM_BUG_ON(__i915_gem_active_peek(&engine->timeline.last_request));
49584954
GEM_BUG_ON(engine->last_retired_context != kernel_context);
49594955
}
49604956
}
@@ -5603,12 +5599,6 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
56035599
INIT_LIST_HEAD(&dev_priv->gt.timelines);
56045600
INIT_LIST_HEAD(&dev_priv->gt.active_rings);
56055601

5606-
mutex_lock(&dev_priv->drm.struct_mutex);
5607-
err = i915_gem_timeline_init__global(dev_priv);
5608-
mutex_unlock(&dev_priv->drm.struct_mutex);
5609-
if (err)
5610-
goto err_priorities;
5611-
56125602
i915_gem_init__mm(dev_priv);
56135603

56145604
INIT_DELAYED_WORK(&dev_priv->gt.retire_work,
@@ -5628,8 +5618,6 @@ int i915_gem_init_early(struct drm_i915_private *dev_priv)
56285618

56295619
return 0;
56305620

5631-
err_priorities:
5632-
kmem_cache_destroy(dev_priv->priorities);
56335621
err_dependencies:
56345622
kmem_cache_destroy(dev_priv->dependencies);
56355623
err_requests:
@@ -5650,12 +5638,7 @@ void i915_gem_cleanup_early(struct drm_i915_private *dev_priv)
56505638
GEM_BUG_ON(!llist_empty(&dev_priv->mm.free_list));
56515639
GEM_BUG_ON(atomic_read(&dev_priv->mm.free_count));
56525640
WARN_ON(dev_priv->mm.object_count);
5653-
5654-
mutex_lock(&dev_priv->drm.struct_mutex);
5655-
i915_gem_timeline_fini(&dev_priv->gt.legacy_timeline);
5656-
i915_gem_timeline_fini(&dev_priv->gt.execution_timeline);
56575641
WARN_ON(!list_empty(&dev_priv->gt.timelines));
5658-
mutex_unlock(&dev_priv->drm.struct_mutex);
56595642

56605643
kmem_cache_destroy(dev_priv->priorities);
56615644
kmem_cache_destroy(dev_priv->dependencies);

drivers/gpu/drm/i915/i915_gem_context.c

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
122122
lockdep_assert_held(&ctx->i915->drm.struct_mutex);
123123
GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
124124

125-
i915_gem_timeline_free(ctx->timeline);
126125
i915_ppgtt_put(ctx->ppgtt);
127126

128127
for (n = 0; n < ARRAY_SIZE(ctx->__engine); n++) {
@@ -377,18 +376,6 @@ i915_gem_create_context(struct drm_i915_private *dev_priv,
377376
ctx->desc_template = default_desc_template(dev_priv, ppgtt);
378377
}
379378

380-
if (HAS_EXECLISTS(dev_priv)) {
381-
struct i915_gem_timeline *timeline;
382-
383-
timeline = i915_gem_timeline_create(dev_priv, ctx->name);
384-
if (IS_ERR(timeline)) {
385-
__destroy_hw_context(ctx, file_priv);
386-
return ERR_CAST(timeline);
387-
}
388-
389-
ctx->timeline = timeline;
390-
}
391-
392379
trace_i915_context_create(ctx);
393380

394381
return ctx;
@@ -590,19 +577,29 @@ void i915_gem_context_close(struct drm_file *file)
590577
idr_destroy(&file_priv->context_idr);
591578
}
592579

593-
static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
580+
static struct i915_request *
581+
last_request_on_engine(struct i915_timeline *timeline,
582+
struct intel_engine_cs *engine)
594583
{
595-
struct i915_gem_timeline *timeline;
584+
struct i915_request *rq;
596585

597-
list_for_each_entry(timeline, &engine->i915->gt.timelines, link) {
598-
struct intel_timeline *tl;
586+
if (timeline == &engine->timeline)
587+
return NULL;
599588

600-
if (timeline == &engine->i915->gt.execution_timeline)
601-
continue;
589+
rq = i915_gem_active_raw(&timeline->last_request,
590+
&engine->i915->drm.struct_mutex);
591+
if (rq && rq->engine == engine)
592+
return rq;
593+
594+
return NULL;
595+
}
602596

603-
tl = &timeline->engine[engine->id];
604-
if (i915_gem_active_peek(&tl->last_request,
605-
&engine->i915->drm.struct_mutex))
597+
static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
598+
{
599+
struct i915_timeline *timeline;
600+
601+
list_for_each_entry(timeline, &engine->i915->gt.timelines, link) {
602+
if (last_request_on_engine(timeline, engine))
606603
return false;
607604
}
608605

@@ -612,7 +609,7 @@ static bool engine_has_idle_kernel_context(struct intel_engine_cs *engine)
612609
int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
613610
{
614611
struct intel_engine_cs *engine;
615-
struct i915_gem_timeline *timeline;
612+
struct i915_timeline *timeline;
616613
enum intel_engine_id id;
617614

618615
lockdep_assert_held(&dev_priv->drm.struct_mutex);
@@ -632,11 +629,8 @@ int i915_gem_switch_to_kernel_context(struct drm_i915_private *dev_priv)
632629
/* Queue this switch after all other activity */
633630
list_for_each_entry(timeline, &dev_priv->gt.timelines, link) {
634631
struct i915_request *prev;
635-
struct intel_timeline *tl;
636632

637-
tl = &timeline->engine[engine->id];
638-
prev = i915_gem_active_raw(&tl->last_request,
639-
&dev_priv->drm.struct_mutex);
633+
prev = last_request_on_engine(timeline, engine);
640634
if (prev)
641635
i915_sw_fence_await_sw_fence_gfp(&rq->submit,
642636
&prev->submit,

0 commit comments

Comments
 (0)