Skip to content

Commit 85fddf0

Browse files
committed
drm/i915: Introduce a context barrier callback
In the next patch, we will want to update live state within a context. As this state may be in use by the GPU and we haven't been explicitly tracking its activity, we instead attach it to a request we send down the context setup with its new state and on retiring that request cleanup the old state as we then know that it is no longer live. Signed-off-by: Chris Wilson <[email protected]> Reviewed-by: Tvrtko Ursulin <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected]
1 parent 831ebf1 commit 85fddf0

File tree

2 files changed

+180
-0
lines changed

2 files changed

+180
-0
lines changed

drivers/gpu/drm/i915/i915_gem_context.c

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,6 +677,80 @@ last_request_on_engine(struct i915_timeline *timeline,
677677
return NULL;
678678
}
679679

680+
struct context_barrier_task {
681+
struct i915_active base;
682+
void (*task)(void *data);
683+
void *data;
684+
};
685+
686+
static void cb_retire(struct i915_active *base)
687+
{
688+
struct context_barrier_task *cb = container_of(base, typeof(*cb), base);
689+
690+
if (cb->task)
691+
cb->task(cb->data);
692+
693+
i915_active_fini(&cb->base);
694+
kfree(cb);
695+
}
696+
697+
I915_SELFTEST_DECLARE(static unsigned long context_barrier_inject_fault);
698+
static int context_barrier_task(struct i915_gem_context *ctx,
699+
unsigned long engines,
700+
void (*task)(void *data),
701+
void *data)
702+
{
703+
struct drm_i915_private *i915 = ctx->i915;
704+
struct context_barrier_task *cb;
705+
struct intel_context *ce;
706+
intel_wakeref_t wakeref;
707+
int err = 0;
708+
709+
lockdep_assert_held(&i915->drm.struct_mutex);
710+
GEM_BUG_ON(!task);
711+
712+
cb = kmalloc(sizeof(*cb), GFP_KERNEL);
713+
if (!cb)
714+
return -ENOMEM;
715+
716+
i915_active_init(i915, &cb->base, cb_retire);
717+
i915_active_acquire(&cb->base);
718+
719+
wakeref = intel_runtime_pm_get(i915);
720+
list_for_each_entry(ce, &ctx->active_engines, active_link) {
721+
struct intel_engine_cs *engine = ce->engine;
722+
struct i915_request *rq;
723+
724+
if (!(ce->engine->mask & engines))
725+
continue;
726+
727+
if (I915_SELFTEST_ONLY(context_barrier_inject_fault &
728+
engine->mask)) {
729+
err = -ENXIO;
730+
break;
731+
}
732+
733+
rq = i915_request_alloc(engine, ctx);
734+
if (IS_ERR(rq)) {
735+
err = PTR_ERR(rq);
736+
break;
737+
}
738+
739+
err = i915_active_ref(&cb->base, rq->fence.context, rq);
740+
i915_request_add(rq);
741+
if (err)
742+
break;
743+
}
744+
intel_runtime_pm_put(i915, wakeref);
745+
746+
cb->task = err ? NULL : task; /* caller needs to unwind instead */
747+
cb->data = data;
748+
749+
i915_active_release(&cb->base);
750+
751+
return err;
752+
}
753+
680754
int i915_gem_switch_to_kernel_context(struct drm_i915_private *i915,
681755
unsigned long mask)
682756
{

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

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,10 +1594,116 @@ static int igt_switch_to_kernel_context(void *arg)
15941594
return err;
15951595
}
15961596

1597+
static void mock_barrier_task(void *data)
1598+
{
1599+
unsigned int *counter = data;
1600+
1601+
++*counter;
1602+
}
1603+
1604+
static int mock_context_barrier(void *arg)
1605+
{
1606+
#undef pr_fmt
1607+
#define pr_fmt(x) "context_barrier_task():" # x
1608+
struct drm_i915_private *i915 = arg;
1609+
struct i915_gem_context *ctx;
1610+
struct i915_request *rq;
1611+
intel_wakeref_t wakeref;
1612+
unsigned int counter;
1613+
int err;
1614+
1615+
/*
1616+
* The context barrier provides us with a callback after it emits
1617+
* a request; useful for retiring old state after loading new.
1618+
*/
1619+
1620+
mutex_lock(&i915->drm.struct_mutex);
1621+
1622+
ctx = mock_context(i915, "mock");
1623+
if (IS_ERR(ctx)) {
1624+
err = PTR_ERR(ctx);
1625+
goto unlock;
1626+
}
1627+
1628+
counter = 0;
1629+
err = context_barrier_task(ctx, 0, mock_barrier_task, &counter);
1630+
if (err) {
1631+
pr_err("Failed at line %d, err=%d\n", __LINE__, err);
1632+
goto out;
1633+
}
1634+
if (counter == 0) {
1635+
pr_err("Did not retire immediately with 0 engines\n");
1636+
err = -EINVAL;
1637+
goto out;
1638+
}
1639+
1640+
counter = 0;
1641+
err = context_barrier_task(ctx,
1642+
ALL_ENGINES, mock_barrier_task, &counter);
1643+
if (err) {
1644+
pr_err("Failed at line %d, err=%d\n", __LINE__, err);
1645+
goto out;
1646+
}
1647+
if (counter == 0) {
1648+
pr_err("Did not retire immediately for all inactive engines\n");
1649+
err = -EINVAL;
1650+
goto out;
1651+
}
1652+
1653+
rq = ERR_PTR(-ENODEV);
1654+
with_intel_runtime_pm(i915, wakeref)
1655+
rq = i915_request_alloc(i915->engine[RCS0], ctx);
1656+
if (IS_ERR(rq)) {
1657+
pr_err("Request allocation failed!\n");
1658+
goto out;
1659+
}
1660+
i915_request_add(rq);
1661+
GEM_BUG_ON(list_empty(&ctx->active_engines));
1662+
1663+
counter = 0;
1664+
context_barrier_inject_fault = BIT(RCS0);
1665+
err = context_barrier_task(ctx,
1666+
ALL_ENGINES, mock_barrier_task, &counter);
1667+
context_barrier_inject_fault = 0;
1668+
if (err == -ENXIO)
1669+
err = 0;
1670+
else
1671+
pr_err("Did not hit fault injection!\n");
1672+
if (counter != 0) {
1673+
pr_err("Invoked callback on error!\n");
1674+
err = -EIO;
1675+
}
1676+
if (err)
1677+
goto out;
1678+
1679+
counter = 0;
1680+
err = context_barrier_task(ctx,
1681+
ALL_ENGINES, mock_barrier_task, &counter);
1682+
if (err) {
1683+
pr_err("Failed at line %d, err=%d\n", __LINE__, err);
1684+
goto out;
1685+
}
1686+
mock_device_flush(i915);
1687+
if (counter == 0) {
1688+
pr_err("Did not retire on each active engines\n");
1689+
err = -EINVAL;
1690+
goto out;
1691+
}
1692+
1693+
out:
1694+
mock_context_close(ctx);
1695+
unlock:
1696+
mutex_unlock(&i915->drm.struct_mutex);
1697+
return err;
1698+
#undef pr_fmt
1699+
#define pr_fmt(x) x
1700+
}
1701+
15971702
int i915_gem_context_mock_selftests(void)
15981703
{
15991704
static const struct i915_subtest tests[] = {
16001705
SUBTEST(igt_switch_to_kernel_context),
1706+
SUBTEST(mock_context_barrier),
16011707
};
16021708
struct drm_i915_private *i915;
16031709
int err;

0 commit comments

Comments
 (0)