Skip to content

Commit 130a95e

Browse files
committed
drm/i915/gem: Consolidate ctx->engines[] release
Use the same engine_idle_release() routine for cleaning all old ctx->engine[] state, closing any potential races with concurrent execbuf submission. v2ish: Use the ce->pin_count to close the execbuf gap. Closes: https://gitlab.freedesktop.org/drm/intel/issues/1241 Signed-off-by: Chris Wilson <[email protected]> Cc: Tvrtko Ursulin <[email protected]> Reviewed-by: Mika Kuoppala <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 3faf8b8 commit 130a95e

File tree

3 files changed

+105
-92
lines changed

3 files changed

+105
-92
lines changed

drivers/gpu/drm/i915/gem/i915_gem_context.c

Lines changed: 102 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,6 @@ static void __free_engines(struct i915_gem_engines *e, unsigned int count)
242242
if (!e->engines[count])
243243
continue;
244244

245-
RCU_INIT_POINTER(e->engines[count]->gem_context, NULL);
246245
intel_context_put(e->engines[count]);
247246
}
248247
kfree(e);
@@ -255,7 +254,11 @@ static void free_engines(struct i915_gem_engines *e)
255254

256255
static void free_engines_rcu(struct rcu_head *rcu)
257256
{
258-
free_engines(container_of(rcu, struct i915_gem_engines, rcu));
257+
struct i915_gem_engines *engines =
258+
container_of(rcu, struct i915_gem_engines, rcu);
259+
260+
i915_sw_fence_fini(&engines->fence);
261+
free_engines(engines);
259262
}
260263

261264
static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
@@ -269,8 +272,6 @@ static struct i915_gem_engines *default_engines(struct i915_gem_context *ctx)
269272
if (!e)
270273
return ERR_PTR(-ENOMEM);
271274

272-
e->ctx = ctx;
273-
274275
for_each_engine(engine, gt, id) {
275276
struct intel_context *ce;
276277

@@ -304,7 +305,6 @@ static void i915_gem_context_free(struct i915_gem_context *ctx)
304305
list_del(&ctx->link);
305306
spin_unlock(&ctx->i915->gem.contexts.lock);
306307

307-
free_engines(rcu_access_pointer(ctx->engines));
308308
mutex_destroy(&ctx->engines_mutex);
309309

310310
if (ctx->timeline)
@@ -491,30 +491,104 @@ static void kill_engines(struct i915_gem_engines *engines)
491491
static void kill_stale_engines(struct i915_gem_context *ctx)
492492
{
493493
struct i915_gem_engines *pos, *next;
494-
unsigned long flags;
495494

496-
spin_lock_irqsave(&ctx->stale.lock, flags);
495+
spin_lock_irq(&ctx->stale.lock);
496+
GEM_BUG_ON(!i915_gem_context_is_closed(ctx));
497497
list_for_each_entry_safe(pos, next, &ctx->stale.engines, link) {
498-
if (!i915_sw_fence_await(&pos->fence))
498+
if (!i915_sw_fence_await(&pos->fence)) {
499+
list_del_init(&pos->link);
499500
continue;
501+
}
500502

501-
spin_unlock_irqrestore(&ctx->stale.lock, flags);
503+
spin_unlock_irq(&ctx->stale.lock);
502504

503505
kill_engines(pos);
504506

505-
spin_lock_irqsave(&ctx->stale.lock, flags);
507+
spin_lock_irq(&ctx->stale.lock);
508+
GEM_BUG_ON(i915_sw_fence_signaled(&pos->fence));
506509
list_safe_reset_next(pos, next, link);
507510
list_del_init(&pos->link); /* decouple from FENCE_COMPLETE */
508511

509512
i915_sw_fence_complete(&pos->fence);
510513
}
511-
spin_unlock_irqrestore(&ctx->stale.lock, flags);
514+
spin_unlock_irq(&ctx->stale.lock);
512515
}
513516

514517
static void kill_context(struct i915_gem_context *ctx)
515518
{
516519
kill_stale_engines(ctx);
517-
kill_engines(__context_engines_static(ctx));
520+
}
521+
522+
static int engines_notify(struct i915_sw_fence *fence,
523+
enum i915_sw_fence_notify state)
524+
{
525+
struct i915_gem_engines *engines =
526+
container_of(fence, typeof(*engines), fence);
527+
528+
switch (state) {
529+
case FENCE_COMPLETE:
530+
if (!list_empty(&engines->link)) {
531+
struct i915_gem_context *ctx = engines->ctx;
532+
unsigned long flags;
533+
534+
spin_lock_irqsave(&ctx->stale.lock, flags);
535+
list_del(&engines->link);
536+
spin_unlock_irqrestore(&ctx->stale.lock, flags);
537+
}
538+
i915_gem_context_put(engines->ctx);
539+
break;
540+
541+
case FENCE_FREE:
542+
init_rcu_head(&engines->rcu);
543+
call_rcu(&engines->rcu, free_engines_rcu);
544+
break;
545+
}
546+
547+
return NOTIFY_DONE;
548+
}
549+
550+
static void engines_idle_release(struct i915_gem_context *ctx,
551+
struct i915_gem_engines *engines)
552+
{
553+
struct i915_gem_engines_iter it;
554+
struct intel_context *ce;
555+
556+
i915_sw_fence_init(&engines->fence, engines_notify);
557+
INIT_LIST_HEAD(&engines->link);
558+
559+
engines->ctx = i915_gem_context_get(ctx);
560+
561+
for_each_gem_engine(ce, engines, it) {
562+
struct dma_fence *fence;
563+
int err = 0;
564+
565+
/* serialises with execbuf */
566+
RCU_INIT_POINTER(ce->gem_context, NULL);
567+
if (!intel_context_pin_if_active(ce))
568+
continue;
569+
570+
fence = i915_active_fence_get(&ce->timeline->last_request);
571+
if (fence) {
572+
err = i915_sw_fence_await_dma_fence(&engines->fence,
573+
fence, 0,
574+
GFP_KERNEL);
575+
dma_fence_put(fence);
576+
}
577+
intel_context_unpin(ce);
578+
if (err < 0)
579+
goto kill;
580+
}
581+
582+
spin_lock_irq(&ctx->stale.lock);
583+
if (!i915_gem_context_is_closed(ctx))
584+
list_add_tail(&engines->link, &ctx->stale.engines);
585+
spin_unlock_irq(&ctx->stale.lock);
586+
587+
kill:
588+
if (list_empty(&engines->link)) /* raced, already closed */
589+
kill_engines(engines);
590+
591+
i915_sw_fence_commit(&engines->fence);
518592
}
519593

520594
static void set_closed_name(struct i915_gem_context *ctx)
@@ -538,11 +612,16 @@ static void context_close(struct i915_gem_context *ctx)
538612
{
539613
struct i915_address_space *vm;
540614

615+
/* Flush any concurrent set_engines() */
616+
mutex_lock(&ctx->engines_mutex);
617+
engines_idle_release(ctx, rcu_replace_pointer(ctx->engines, NULL, 1));
541618
i915_gem_context_set_closed(ctx);
542-
set_closed_name(ctx);
619+
mutex_unlock(&ctx->engines_mutex);
543620

544621
mutex_lock(&ctx->mutex);
545622

623+
set_closed_name(ctx);
624+
546625
vm = i915_gem_context_vm(ctx);
547626
if (vm)
548627
i915_vm_close(vm);
@@ -1626,77 +1705,6 @@ static const i915_user_extension_fn set_engines__extensions[] = {
16261705
[I915_CONTEXT_ENGINES_EXT_BOND] = set_engines__bond,
16271706
};
16281707

1629-
static int engines_notify(struct i915_sw_fence *fence,
1630-
enum i915_sw_fence_notify state)
1631-
{
1632-
struct i915_gem_engines *engines =
1633-
container_of(fence, typeof(*engines), fence);
1634-
1635-
switch (state) {
1636-
case FENCE_COMPLETE:
1637-
if (!list_empty(&engines->link)) {
1638-
struct i915_gem_context *ctx = engines->ctx;
1639-
unsigned long flags;
1640-
1641-
spin_lock_irqsave(&ctx->stale.lock, flags);
1642-
list_del(&engines->link);
1643-
spin_unlock_irqrestore(&ctx->stale.lock, flags);
1644-
}
1645-
break;
1646-
1647-
case FENCE_FREE:
1648-
init_rcu_head(&engines->rcu);
1649-
call_rcu(&engines->rcu, free_engines_rcu);
1650-
break;
1651-
}
1652-
1653-
return NOTIFY_DONE;
1654-
}
1655-
1656-
static void engines_idle_release(struct i915_gem_engines *engines)
1657-
{
1658-
struct i915_gem_engines_iter it;
1659-
struct intel_context *ce;
1660-
unsigned long flags;
1661-
1662-
GEM_BUG_ON(!engines);
1663-
i915_sw_fence_init(&engines->fence, engines_notify);
1664-
1665-
INIT_LIST_HEAD(&engines->link);
1666-
spin_lock_irqsave(&engines->ctx->stale.lock, flags);
1667-
if (!i915_gem_context_is_closed(engines->ctx))
1668-
list_add(&engines->link, &engines->ctx->stale.engines);
1669-
spin_unlock_irqrestore(&engines->ctx->stale.lock, flags);
1670-
if (list_empty(&engines->link)) /* raced, already closed */
1671-
goto kill;
1672-
1673-
for_each_gem_engine(ce, engines, it) {
1674-
struct dma_fence *fence;
1675-
int err;
1676-
1677-
if (!ce->timeline)
1678-
continue;
1679-
1680-
fence = i915_active_fence_get(&ce->timeline->last_request);
1681-
if (!fence)
1682-
continue;
1683-
1684-
err = i915_sw_fence_await_dma_fence(&engines->fence,
1685-
fence, 0,
1686-
GFP_KERNEL);
1687-
1688-
dma_fence_put(fence);
1689-
if (err < 0)
1690-
goto kill;
1691-
}
1692-
goto out;
1693-
1694-
kill:
1695-
kill_engines(engines);
1696-
out:
1697-
i915_sw_fence_commit(&engines->fence);
1698-
}
1699-
17001708
static int
17011709
set_engines(struct i915_gem_context *ctx,
17021710
const struct drm_i915_gem_context_param *args)
@@ -1739,8 +1747,6 @@ set_engines(struct i915_gem_context *ctx,
17391747
if (!set.engines)
17401748
return -ENOMEM;
17411749

1742-
set.engines->ctx = ctx;
1743-
17441750
for (n = 0; n < num_engines; n++) {
17451751
struct i915_engine_class_instance ci;
17461752
struct intel_engine_cs *engine;
@@ -1793,6 +1799,11 @@ set_engines(struct i915_gem_context *ctx,
17931799

17941800
replace:
17951801
mutex_lock(&ctx->engines_mutex);
1802+
if (i915_gem_context_is_closed(ctx)) {
1803+
mutex_unlock(&ctx->engines_mutex);
1804+
free_engines(set.engines);
1805+
return -ENOENT;
1806+
}
17961807
if (args->size)
17971808
i915_gem_context_set_user_engines(ctx);
17981809
else
@@ -1801,7 +1812,7 @@ set_engines(struct i915_gem_context *ctx,
18011812
mutex_unlock(&ctx->engines_mutex);
18021813

18031814
/* Keep track of old engine sets for kill_context() */
1804-
engines_idle_release(set.engines);
1815+
engines_idle_release(ctx, set.engines);
18051816

18061817
return 0;
18071818
}
@@ -2077,8 +2088,6 @@ static int clone_engines(struct i915_gem_context *dst,
20772088
if (!clone)
20782089
goto err_unlock;
20792090

2080-
clone->ctx = dst;
2081-
20822091
for (n = 0; n < e->num_engines; n++) {
20832092
struct intel_engine_cs *engine;
20842093

@@ -2121,8 +2130,7 @@ static int clone_engines(struct i915_gem_context *dst,
21212130
i915_gem_context_unlock_engines(src);
21222131

21232132
/* Serialised by constructor */
2124-
free_engines(__context_engines_static(dst));
2125-
RCU_INIT_POINTER(dst->engines, clone);
2133+
engines_idle_release(dst, rcu_replace_pointer(dst->engines, clone, 1));
21262134
if (user_engines)
21272135
i915_gem_context_set_user_engines(dst);
21282136
else
@@ -2553,6 +2561,9 @@ i915_gem_engines_iter_next(struct i915_gem_engines_iter *it)
25532561
const struct i915_gem_engines *e = it->engines;
25542562
struct intel_context *ctx;
25552563

2564+
if (unlikely(!e))
2565+
return NULL;
2566+
25562567
do {
25572568
if (it->idx >= e->num_engines)
25582569
return NULL;

drivers/gpu/drm/i915/gem/i915_gem_context.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,6 @@ static inline void
207207
i915_gem_engines_iter_init(struct i915_gem_engines_iter *it,
208208
struct i915_gem_engines *engines)
209209
{
210-
GEM_BUG_ON(!engines);
211210
it->engines = engines;
212211
it->idx = 0;
213212
}

drivers/gpu/drm/i915/gem/selftests/mock_context.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ mock_context(struct drm_i915_private *i915,
2323
INIT_LIST_HEAD(&ctx->link);
2424
ctx->i915 = i915;
2525

26+
spin_lock_init(&ctx->stale.lock);
27+
INIT_LIST_HEAD(&ctx->stale.engines);
28+
2629
i915_gem_context_set_persistence(ctx);
2730

2831
mutex_init(&ctx->engines_mutex);

0 commit comments

Comments
 (0)