162306a36Sopenharmony_ci// SPDX-License-Identifier: MIT
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright © 2019 Intel Corporation
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include "gem/i915_gem_context.h"
762306a36Sopenharmony_ci#include "gem/i915_gem_pm.h"
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "i915_drv.h"
1062306a36Sopenharmony_ci#include "i915_trace.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include "intel_context.h"
1362306a36Sopenharmony_ci#include "intel_engine.h"
1462306a36Sopenharmony_ci#include "intel_engine_pm.h"
1562306a36Sopenharmony_ci#include "intel_ring.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_cistatic struct kmem_cache *slab_ce;
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic struct intel_context *intel_context_alloc(void)
2062306a36Sopenharmony_ci{
2162306a36Sopenharmony_ci	return kmem_cache_zalloc(slab_ce, GFP_KERNEL);
2262306a36Sopenharmony_ci}
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_cistatic void rcu_context_free(struct rcu_head *rcu)
2562306a36Sopenharmony_ci{
2662306a36Sopenharmony_ci	struct intel_context *ce = container_of(rcu, typeof(*ce), rcu);
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci	trace_intel_context_free(ce);
2962306a36Sopenharmony_ci	kmem_cache_free(slab_ce, ce);
3062306a36Sopenharmony_ci}
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_civoid intel_context_free(struct intel_context *ce)
3362306a36Sopenharmony_ci{
3462306a36Sopenharmony_ci	call_rcu(&ce->rcu, rcu_context_free);
3562306a36Sopenharmony_ci}
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistruct intel_context *
3862306a36Sopenharmony_ciintel_context_create(struct intel_engine_cs *engine)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	struct intel_context *ce;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	ce = intel_context_alloc();
4362306a36Sopenharmony_ci	if (!ce)
4462306a36Sopenharmony_ci		return ERR_PTR(-ENOMEM);
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	intel_context_init(ce, engine);
4762306a36Sopenharmony_ci	trace_intel_context_create(ce);
4862306a36Sopenharmony_ci	return ce;
4962306a36Sopenharmony_ci}
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ciint intel_context_alloc_state(struct intel_context *ce)
5262306a36Sopenharmony_ci{
5362306a36Sopenharmony_ci	int err = 0;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	if (mutex_lock_interruptible(&ce->pin_mutex))
5662306a36Sopenharmony_ci		return -EINTR;
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci	if (!test_bit(CONTEXT_ALLOC_BIT, &ce->flags)) {
5962306a36Sopenharmony_ci		if (intel_context_is_banned(ce)) {
6062306a36Sopenharmony_ci			err = -EIO;
6162306a36Sopenharmony_ci			goto unlock;
6262306a36Sopenharmony_ci		}
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_ci		err = ce->ops->alloc(ce);
6562306a36Sopenharmony_ci		if (unlikely(err))
6662306a36Sopenharmony_ci			goto unlock;
6762306a36Sopenharmony_ci
6862306a36Sopenharmony_ci		set_bit(CONTEXT_ALLOC_BIT, &ce->flags);
6962306a36Sopenharmony_ci	}
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ciunlock:
7262306a36Sopenharmony_ci	mutex_unlock(&ce->pin_mutex);
7362306a36Sopenharmony_ci	return err;
7462306a36Sopenharmony_ci}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic int intel_context_active_acquire(struct intel_context *ce)
7762306a36Sopenharmony_ci{
7862306a36Sopenharmony_ci	int err;
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci	__i915_active_acquire(&ce->active);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (intel_context_is_barrier(ce) || intel_engine_uses_guc(ce->engine) ||
8362306a36Sopenharmony_ci	    intel_context_is_parallel(ce))
8462306a36Sopenharmony_ci		return 0;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	/* Preallocate tracking nodes */
8762306a36Sopenharmony_ci	err = i915_active_acquire_preallocate_barrier(&ce->active,
8862306a36Sopenharmony_ci						      ce->engine);
8962306a36Sopenharmony_ci	if (err)
9062306a36Sopenharmony_ci		i915_active_release(&ce->active);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci	return err;
9362306a36Sopenharmony_ci}
9462306a36Sopenharmony_ci
9562306a36Sopenharmony_cistatic void intel_context_active_release(struct intel_context *ce)
9662306a36Sopenharmony_ci{
9762306a36Sopenharmony_ci	/* Nodes preallocated in intel_context_active() */
9862306a36Sopenharmony_ci	i915_active_acquire_barrier(&ce->active);
9962306a36Sopenharmony_ci	i915_active_release(&ce->active);
10062306a36Sopenharmony_ci}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_cistatic int __context_pin_state(struct i915_vma *vma, struct i915_gem_ww_ctx *ww)
10362306a36Sopenharmony_ci{
10462306a36Sopenharmony_ci	unsigned int bias = i915_ggtt_pin_bias(vma) | PIN_OFFSET_BIAS;
10562306a36Sopenharmony_ci	int err;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	err = i915_ggtt_pin(vma, ww, 0, bias | PIN_HIGH);
10862306a36Sopenharmony_ci	if (err)
10962306a36Sopenharmony_ci		return err;
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	err = i915_active_acquire(&vma->active);
11262306a36Sopenharmony_ci	if (err)
11362306a36Sopenharmony_ci		goto err_unpin;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	/*
11662306a36Sopenharmony_ci	 * And mark it as a globally pinned object to let the shrinker know
11762306a36Sopenharmony_ci	 * it cannot reclaim the object until we release it.
11862306a36Sopenharmony_ci	 */
11962306a36Sopenharmony_ci	i915_vma_make_unshrinkable(vma);
12062306a36Sopenharmony_ci	vma->obj->mm.dirty = true;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	return 0;
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cierr_unpin:
12562306a36Sopenharmony_ci	i915_vma_unpin(vma);
12662306a36Sopenharmony_ci	return err;
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic void __context_unpin_state(struct i915_vma *vma)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	i915_vma_make_shrinkable(vma);
13262306a36Sopenharmony_ci	i915_active_release(&vma->active);
13362306a36Sopenharmony_ci	__i915_vma_unpin(vma);
13462306a36Sopenharmony_ci}
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_cistatic int __ring_active(struct intel_ring *ring,
13762306a36Sopenharmony_ci			 struct i915_gem_ww_ctx *ww)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	int err;
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ci	err = intel_ring_pin(ring, ww);
14262306a36Sopenharmony_ci	if (err)
14362306a36Sopenharmony_ci		return err;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	err = i915_active_acquire(&ring->vma->active);
14662306a36Sopenharmony_ci	if (err)
14762306a36Sopenharmony_ci		goto err_pin;
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_ci	return 0;
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cierr_pin:
15262306a36Sopenharmony_ci	intel_ring_unpin(ring);
15362306a36Sopenharmony_ci	return err;
15462306a36Sopenharmony_ci}
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_cistatic void __ring_retire(struct intel_ring *ring)
15762306a36Sopenharmony_ci{
15862306a36Sopenharmony_ci	i915_active_release(&ring->vma->active);
15962306a36Sopenharmony_ci	intel_ring_unpin(ring);
16062306a36Sopenharmony_ci}
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_cistatic int intel_context_pre_pin(struct intel_context *ce,
16362306a36Sopenharmony_ci				 struct i915_gem_ww_ctx *ww)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	int err;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	CE_TRACE(ce, "active\n");
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	err = __ring_active(ce->ring, ww);
17062306a36Sopenharmony_ci	if (err)
17162306a36Sopenharmony_ci		return err;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	err = intel_timeline_pin(ce->timeline, ww);
17462306a36Sopenharmony_ci	if (err)
17562306a36Sopenharmony_ci		goto err_ring;
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci	if (!ce->state)
17862306a36Sopenharmony_ci		return 0;
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	err = __context_pin_state(ce->state, ww);
18162306a36Sopenharmony_ci	if (err)
18262306a36Sopenharmony_ci		goto err_timeline;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	return 0;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cierr_timeline:
18862306a36Sopenharmony_ci	intel_timeline_unpin(ce->timeline);
18962306a36Sopenharmony_cierr_ring:
19062306a36Sopenharmony_ci	__ring_retire(ce->ring);
19162306a36Sopenharmony_ci	return err;
19262306a36Sopenharmony_ci}
19362306a36Sopenharmony_ci
19462306a36Sopenharmony_cistatic void intel_context_post_unpin(struct intel_context *ce)
19562306a36Sopenharmony_ci{
19662306a36Sopenharmony_ci	if (ce->state)
19762306a36Sopenharmony_ci		__context_unpin_state(ce->state);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	intel_timeline_unpin(ce->timeline);
20062306a36Sopenharmony_ci	__ring_retire(ce->ring);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_ciint __intel_context_do_pin_ww(struct intel_context *ce,
20462306a36Sopenharmony_ci			      struct i915_gem_ww_ctx *ww)
20562306a36Sopenharmony_ci{
20662306a36Sopenharmony_ci	bool handoff = false;
20762306a36Sopenharmony_ci	void *vaddr;
20862306a36Sopenharmony_ci	int err = 0;
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	if (unlikely(!test_bit(CONTEXT_ALLOC_BIT, &ce->flags))) {
21162306a36Sopenharmony_ci		err = intel_context_alloc_state(ce);
21262306a36Sopenharmony_ci		if (err)
21362306a36Sopenharmony_ci			return err;
21462306a36Sopenharmony_ci	}
21562306a36Sopenharmony_ci
21662306a36Sopenharmony_ci	/*
21762306a36Sopenharmony_ci	 * We always pin the context/ring/timeline here, to ensure a pin
21862306a36Sopenharmony_ci	 * refcount for __intel_context_active(), which prevent a lock
21962306a36Sopenharmony_ci	 * inversion of ce->pin_mutex vs dma_resv_lock().
22062306a36Sopenharmony_ci	 */
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	err = i915_gem_object_lock(ce->timeline->hwsp_ggtt->obj, ww);
22362306a36Sopenharmony_ci	if (!err)
22462306a36Sopenharmony_ci		err = i915_gem_object_lock(ce->ring->vma->obj, ww);
22562306a36Sopenharmony_ci	if (!err && ce->state)
22662306a36Sopenharmony_ci		err = i915_gem_object_lock(ce->state->obj, ww);
22762306a36Sopenharmony_ci	if (!err)
22862306a36Sopenharmony_ci		err = intel_context_pre_pin(ce, ww);
22962306a36Sopenharmony_ci	if (err)
23062306a36Sopenharmony_ci		return err;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	err = ce->ops->pre_pin(ce, ww, &vaddr);
23362306a36Sopenharmony_ci	if (err)
23462306a36Sopenharmony_ci		goto err_ctx_unpin;
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	err = i915_active_acquire(&ce->active);
23762306a36Sopenharmony_ci	if (err)
23862306a36Sopenharmony_ci		goto err_post_unpin;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	err = mutex_lock_interruptible(&ce->pin_mutex);
24162306a36Sopenharmony_ci	if (err)
24262306a36Sopenharmony_ci		goto err_release;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	intel_engine_pm_might_get(ce->engine);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (unlikely(intel_context_is_closed(ce))) {
24762306a36Sopenharmony_ci		err = -ENOENT;
24862306a36Sopenharmony_ci		goto err_unlock;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (likely(!atomic_add_unless(&ce->pin_count, 1, 0))) {
25262306a36Sopenharmony_ci		err = intel_context_active_acquire(ce);
25362306a36Sopenharmony_ci		if (unlikely(err))
25462306a36Sopenharmony_ci			goto err_unlock;
25562306a36Sopenharmony_ci
25662306a36Sopenharmony_ci		err = ce->ops->pin(ce, vaddr);
25762306a36Sopenharmony_ci		if (err) {
25862306a36Sopenharmony_ci			intel_context_active_release(ce);
25962306a36Sopenharmony_ci			goto err_unlock;
26062306a36Sopenharmony_ci		}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		CE_TRACE(ce, "pin ring:{start:%08x, head:%04x, tail:%04x}\n",
26362306a36Sopenharmony_ci			 i915_ggtt_offset(ce->ring->vma),
26462306a36Sopenharmony_ci			 ce->ring->head, ce->ring->tail);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci		handoff = true;
26762306a36Sopenharmony_ci		smp_mb__before_atomic(); /* flush pin before it is visible */
26862306a36Sopenharmony_ci		atomic_inc(&ce->pin_count);
26962306a36Sopenharmony_ci	}
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci	GEM_BUG_ON(!intel_context_is_pinned(ce)); /* no overflow! */
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_ci	trace_intel_context_do_pin(ce);
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_cierr_unlock:
27662306a36Sopenharmony_ci	mutex_unlock(&ce->pin_mutex);
27762306a36Sopenharmony_cierr_release:
27862306a36Sopenharmony_ci	i915_active_release(&ce->active);
27962306a36Sopenharmony_cierr_post_unpin:
28062306a36Sopenharmony_ci	if (!handoff)
28162306a36Sopenharmony_ci		ce->ops->post_unpin(ce);
28262306a36Sopenharmony_cierr_ctx_unpin:
28362306a36Sopenharmony_ci	intel_context_post_unpin(ce);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	/*
28662306a36Sopenharmony_ci	 * Unlock the hwsp_ggtt object since it's shared.
28762306a36Sopenharmony_ci	 * In principle we can unlock all the global state locked above
28862306a36Sopenharmony_ci	 * since it's pinned and doesn't need fencing, and will
28962306a36Sopenharmony_ci	 * thus remain resident until it is explicitly unpinned.
29062306a36Sopenharmony_ci	 */
29162306a36Sopenharmony_ci	i915_gem_ww_unlock_single(ce->timeline->hwsp_ggtt->obj);
29262306a36Sopenharmony_ci
29362306a36Sopenharmony_ci	return err;
29462306a36Sopenharmony_ci}
29562306a36Sopenharmony_ci
29662306a36Sopenharmony_ciint __intel_context_do_pin(struct intel_context *ce)
29762306a36Sopenharmony_ci{
29862306a36Sopenharmony_ci	struct i915_gem_ww_ctx ww;
29962306a36Sopenharmony_ci	int err;
30062306a36Sopenharmony_ci
30162306a36Sopenharmony_ci	i915_gem_ww_ctx_init(&ww, true);
30262306a36Sopenharmony_ciretry:
30362306a36Sopenharmony_ci	err = __intel_context_do_pin_ww(ce, &ww);
30462306a36Sopenharmony_ci	if (err == -EDEADLK) {
30562306a36Sopenharmony_ci		err = i915_gem_ww_ctx_backoff(&ww);
30662306a36Sopenharmony_ci		if (!err)
30762306a36Sopenharmony_ci			goto retry;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci	i915_gem_ww_ctx_fini(&ww);
31062306a36Sopenharmony_ci	return err;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_civoid __intel_context_do_unpin(struct intel_context *ce, int sub)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	if (!atomic_sub_and_test(sub, &ce->pin_count))
31662306a36Sopenharmony_ci		return;
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_ci	CE_TRACE(ce, "unpin\n");
31962306a36Sopenharmony_ci	ce->ops->unpin(ce);
32062306a36Sopenharmony_ci	ce->ops->post_unpin(ce);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	/*
32362306a36Sopenharmony_ci	 * Once released, we may asynchronously drop the active reference.
32462306a36Sopenharmony_ci	 * As that may be the only reference keeping the context alive,
32562306a36Sopenharmony_ci	 * take an extra now so that it is not freed before we finish
32662306a36Sopenharmony_ci	 * dereferencing it.
32762306a36Sopenharmony_ci	 */
32862306a36Sopenharmony_ci	intel_context_get(ce);
32962306a36Sopenharmony_ci	intel_context_active_release(ce);
33062306a36Sopenharmony_ci	trace_intel_context_do_unpin(ce);
33162306a36Sopenharmony_ci	intel_context_put(ce);
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic void __intel_context_retire(struct i915_active *active)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	struct intel_context *ce = container_of(active, typeof(*ce), active);
33762306a36Sopenharmony_ci
33862306a36Sopenharmony_ci	CE_TRACE(ce, "retire runtime: { total:%lluns, avg:%lluns }\n",
33962306a36Sopenharmony_ci		 intel_context_get_total_runtime_ns(ce),
34062306a36Sopenharmony_ci		 intel_context_get_avg_runtime_ns(ce));
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_ci	set_bit(CONTEXT_VALID_BIT, &ce->flags);
34362306a36Sopenharmony_ci	intel_context_post_unpin(ce);
34462306a36Sopenharmony_ci	intel_context_put(ce);
34562306a36Sopenharmony_ci}
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_cistatic int __intel_context_active(struct i915_active *active)
34862306a36Sopenharmony_ci{
34962306a36Sopenharmony_ci	struct intel_context *ce = container_of(active, typeof(*ce), active);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	intel_context_get(ce);
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	/* everything should already be activated by intel_context_pre_pin() */
35462306a36Sopenharmony_ci	GEM_WARN_ON(!i915_active_acquire_if_busy(&ce->ring->vma->active));
35562306a36Sopenharmony_ci	__intel_ring_pin(ce->ring);
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	__intel_timeline_pin(ce->timeline);
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_ci	if (ce->state) {
36062306a36Sopenharmony_ci		GEM_WARN_ON(!i915_active_acquire_if_busy(&ce->state->active));
36162306a36Sopenharmony_ci		__i915_vma_pin(ce->state);
36262306a36Sopenharmony_ci		i915_vma_make_unshrinkable(ce->state);
36362306a36Sopenharmony_ci	}
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	return 0;
36662306a36Sopenharmony_ci}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_cistatic int
36962306a36Sopenharmony_cisw_fence_dummy_notify(struct i915_sw_fence *sf,
37062306a36Sopenharmony_ci		      enum i915_sw_fence_notify state)
37162306a36Sopenharmony_ci{
37262306a36Sopenharmony_ci	return NOTIFY_DONE;
37362306a36Sopenharmony_ci}
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_civoid
37662306a36Sopenharmony_ciintel_context_init(struct intel_context *ce, struct intel_engine_cs *engine)
37762306a36Sopenharmony_ci{
37862306a36Sopenharmony_ci	GEM_BUG_ON(!engine->cops);
37962306a36Sopenharmony_ci	GEM_BUG_ON(!engine->gt->vm);
38062306a36Sopenharmony_ci
38162306a36Sopenharmony_ci	kref_init(&ce->ref);
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	ce->engine = engine;
38462306a36Sopenharmony_ci	ce->ops = engine->cops;
38562306a36Sopenharmony_ci	ce->sseu = engine->sseu;
38662306a36Sopenharmony_ci	ce->ring = NULL;
38762306a36Sopenharmony_ci	ce->ring_size = SZ_4K;
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	ewma_runtime_init(&ce->stats.runtime.avg);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	ce->vm = i915_vm_get(engine->gt->vm);
39262306a36Sopenharmony_ci
39362306a36Sopenharmony_ci	/* NB ce->signal_link/lock is used under RCU */
39462306a36Sopenharmony_ci	spin_lock_init(&ce->signal_lock);
39562306a36Sopenharmony_ci	INIT_LIST_HEAD(&ce->signals);
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	mutex_init(&ce->pin_mutex);
39862306a36Sopenharmony_ci
39962306a36Sopenharmony_ci	spin_lock_init(&ce->guc_state.lock);
40062306a36Sopenharmony_ci	INIT_LIST_HEAD(&ce->guc_state.fences);
40162306a36Sopenharmony_ci	INIT_LIST_HEAD(&ce->guc_state.requests);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	ce->guc_id.id = GUC_INVALID_CONTEXT_ID;
40462306a36Sopenharmony_ci	INIT_LIST_HEAD(&ce->guc_id.link);
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci	INIT_LIST_HEAD(&ce->destroyed_link);
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	INIT_LIST_HEAD(&ce->parallel.child_list);
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci	/*
41162306a36Sopenharmony_ci	 * Initialize fence to be complete as this is expected to be complete
41262306a36Sopenharmony_ci	 * unless there is a pending schedule disable outstanding.
41362306a36Sopenharmony_ci	 */
41462306a36Sopenharmony_ci	i915_sw_fence_init(&ce->guc_state.blocked,
41562306a36Sopenharmony_ci			   sw_fence_dummy_notify);
41662306a36Sopenharmony_ci	i915_sw_fence_commit(&ce->guc_state.blocked);
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	i915_active_init(&ce->active,
41962306a36Sopenharmony_ci			 __intel_context_active, __intel_context_retire, 0);
42062306a36Sopenharmony_ci}
42162306a36Sopenharmony_ci
42262306a36Sopenharmony_civoid intel_context_fini(struct intel_context *ce)
42362306a36Sopenharmony_ci{
42462306a36Sopenharmony_ci	struct intel_context *child, *next;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	if (ce->timeline)
42762306a36Sopenharmony_ci		intel_timeline_put(ce->timeline);
42862306a36Sopenharmony_ci	i915_vm_put(ce->vm);
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	/* Need to put the creation ref for the children */
43162306a36Sopenharmony_ci	if (intel_context_is_parent(ce))
43262306a36Sopenharmony_ci		for_each_child_safe(ce, child, next)
43362306a36Sopenharmony_ci			intel_context_put(child);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	mutex_destroy(&ce->pin_mutex);
43662306a36Sopenharmony_ci	i915_active_fini(&ce->active);
43762306a36Sopenharmony_ci	i915_sw_fence_fini(&ce->guc_state.blocked);
43862306a36Sopenharmony_ci}
43962306a36Sopenharmony_ci
44062306a36Sopenharmony_civoid i915_context_module_exit(void)
44162306a36Sopenharmony_ci{
44262306a36Sopenharmony_ci	kmem_cache_destroy(slab_ce);
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ciint __init i915_context_module_init(void)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	slab_ce = KMEM_CACHE(intel_context, SLAB_HWCACHE_ALIGN);
44862306a36Sopenharmony_ci	if (!slab_ce)
44962306a36Sopenharmony_ci		return -ENOMEM;
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci	return 0;
45262306a36Sopenharmony_ci}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_civoid intel_context_enter_engine(struct intel_context *ce)
45562306a36Sopenharmony_ci{
45662306a36Sopenharmony_ci	intel_engine_pm_get(ce->engine);
45762306a36Sopenharmony_ci	intel_timeline_enter(ce->timeline);
45862306a36Sopenharmony_ci}
45962306a36Sopenharmony_ci
46062306a36Sopenharmony_civoid intel_context_exit_engine(struct intel_context *ce)
46162306a36Sopenharmony_ci{
46262306a36Sopenharmony_ci	intel_timeline_exit(ce->timeline);
46362306a36Sopenharmony_ci	intel_engine_pm_put(ce->engine);
46462306a36Sopenharmony_ci}
46562306a36Sopenharmony_ci
46662306a36Sopenharmony_ciint intel_context_prepare_remote_request(struct intel_context *ce,
46762306a36Sopenharmony_ci					 struct i915_request *rq)
46862306a36Sopenharmony_ci{
46962306a36Sopenharmony_ci	struct intel_timeline *tl = ce->timeline;
47062306a36Sopenharmony_ci	int err;
47162306a36Sopenharmony_ci
47262306a36Sopenharmony_ci	/* Only suitable for use in remotely modifying this context */
47362306a36Sopenharmony_ci	GEM_BUG_ON(rq->context == ce);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	if (rcu_access_pointer(rq->timeline) != tl) { /* timeline sharing! */
47662306a36Sopenharmony_ci		/* Queue this switch after current activity by this context. */
47762306a36Sopenharmony_ci		err = i915_active_fence_set(&tl->last_request, rq);
47862306a36Sopenharmony_ci		if (err)
47962306a36Sopenharmony_ci			return err;
48062306a36Sopenharmony_ci	}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci	/*
48362306a36Sopenharmony_ci	 * Guarantee context image and the timeline remains pinned until the
48462306a36Sopenharmony_ci	 * modifying request is retired by setting the ce activity tracker.
48562306a36Sopenharmony_ci	 *
48662306a36Sopenharmony_ci	 * But we only need to take one pin on the account of it. Or in other
48762306a36Sopenharmony_ci	 * words transfer the pinned ce object to tracked active request.
48862306a36Sopenharmony_ci	 */
48962306a36Sopenharmony_ci	GEM_BUG_ON(i915_active_is_idle(&ce->active));
49062306a36Sopenharmony_ci	return i915_active_add_request(&ce->active, rq);
49162306a36Sopenharmony_ci}
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_cistruct i915_request *intel_context_create_request(struct intel_context *ce)
49462306a36Sopenharmony_ci{
49562306a36Sopenharmony_ci	struct i915_gem_ww_ctx ww;
49662306a36Sopenharmony_ci	struct i915_request *rq;
49762306a36Sopenharmony_ci	int err;
49862306a36Sopenharmony_ci
49962306a36Sopenharmony_ci	i915_gem_ww_ctx_init(&ww, true);
50062306a36Sopenharmony_ciretry:
50162306a36Sopenharmony_ci	err = intel_context_pin_ww(ce, &ww);
50262306a36Sopenharmony_ci	if (!err) {
50362306a36Sopenharmony_ci		rq = i915_request_create(ce);
50462306a36Sopenharmony_ci		intel_context_unpin(ce);
50562306a36Sopenharmony_ci	} else if (err == -EDEADLK) {
50662306a36Sopenharmony_ci		err = i915_gem_ww_ctx_backoff(&ww);
50762306a36Sopenharmony_ci		if (!err)
50862306a36Sopenharmony_ci			goto retry;
50962306a36Sopenharmony_ci		rq = ERR_PTR(err);
51062306a36Sopenharmony_ci	} else {
51162306a36Sopenharmony_ci		rq = ERR_PTR(err);
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	i915_gem_ww_ctx_fini(&ww);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	if (IS_ERR(rq))
51762306a36Sopenharmony_ci		return rq;
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/*
52062306a36Sopenharmony_ci	 * timeline->mutex should be the inner lock, but is used as outer lock.
52162306a36Sopenharmony_ci	 * Hack around this to shut up lockdep in selftests..
52262306a36Sopenharmony_ci	 */
52362306a36Sopenharmony_ci	lockdep_unpin_lock(&ce->timeline->mutex, rq->cookie);
52462306a36Sopenharmony_ci	mutex_release(&ce->timeline->mutex.dep_map, _RET_IP_);
52562306a36Sopenharmony_ci	mutex_acquire(&ce->timeline->mutex.dep_map, SINGLE_DEPTH_NESTING, 0, _RET_IP_);
52662306a36Sopenharmony_ci	rq->cookie = lockdep_pin_lock(&ce->timeline->mutex);
52762306a36Sopenharmony_ci
52862306a36Sopenharmony_ci	return rq;
52962306a36Sopenharmony_ci}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_cistruct i915_request *intel_context_get_active_request(struct intel_context *ce)
53262306a36Sopenharmony_ci{
53362306a36Sopenharmony_ci	struct intel_context *parent = intel_context_to_parent(ce);
53462306a36Sopenharmony_ci	struct i915_request *rq, *active = NULL;
53562306a36Sopenharmony_ci	unsigned long flags;
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci	GEM_BUG_ON(!intel_engine_uses_guc(ce->engine));
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	/*
54062306a36Sopenharmony_ci	 * We search the parent list to find an active request on the submitted
54162306a36Sopenharmony_ci	 * context. The parent list contains the requests for all the contexts
54262306a36Sopenharmony_ci	 * in the relationship so we have to do a compare of each request's
54362306a36Sopenharmony_ci	 * context.
54462306a36Sopenharmony_ci	 */
54562306a36Sopenharmony_ci	spin_lock_irqsave(&parent->guc_state.lock, flags);
54662306a36Sopenharmony_ci	list_for_each_entry_reverse(rq, &parent->guc_state.requests,
54762306a36Sopenharmony_ci				    sched.link) {
54862306a36Sopenharmony_ci		if (rq->context != ce)
54962306a36Sopenharmony_ci			continue;
55062306a36Sopenharmony_ci		if (i915_request_completed(rq))
55162306a36Sopenharmony_ci			break;
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci		active = rq;
55462306a36Sopenharmony_ci	}
55562306a36Sopenharmony_ci	if (active)
55662306a36Sopenharmony_ci		active = i915_request_get_rcu(active);
55762306a36Sopenharmony_ci	spin_unlock_irqrestore(&parent->guc_state.lock, flags);
55862306a36Sopenharmony_ci
55962306a36Sopenharmony_ci	return active;
56062306a36Sopenharmony_ci}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_civoid intel_context_bind_parent_child(struct intel_context *parent,
56362306a36Sopenharmony_ci				     struct intel_context *child)
56462306a36Sopenharmony_ci{
56562306a36Sopenharmony_ci	/*
56662306a36Sopenharmony_ci	 * Callers responsibility to validate that this function is used
56762306a36Sopenharmony_ci	 * correctly but we use GEM_BUG_ON here ensure that they do.
56862306a36Sopenharmony_ci	 */
56962306a36Sopenharmony_ci	GEM_BUG_ON(intel_context_is_pinned(parent));
57062306a36Sopenharmony_ci	GEM_BUG_ON(intel_context_is_child(parent));
57162306a36Sopenharmony_ci	GEM_BUG_ON(intel_context_is_pinned(child));
57262306a36Sopenharmony_ci	GEM_BUG_ON(intel_context_is_child(child));
57362306a36Sopenharmony_ci	GEM_BUG_ON(intel_context_is_parent(child));
57462306a36Sopenharmony_ci
57562306a36Sopenharmony_ci	parent->parallel.child_index = parent->parallel.number_children++;
57662306a36Sopenharmony_ci	list_add_tail(&child->parallel.child_link,
57762306a36Sopenharmony_ci		      &parent->parallel.child_list);
57862306a36Sopenharmony_ci	child->parallel.parent = parent;
57962306a36Sopenharmony_ci}
58062306a36Sopenharmony_ci
58162306a36Sopenharmony_ciu64 intel_context_get_total_runtime_ns(struct intel_context *ce)
58262306a36Sopenharmony_ci{
58362306a36Sopenharmony_ci	u64 total, active;
58462306a36Sopenharmony_ci
58562306a36Sopenharmony_ci	if (ce->ops->update_stats)
58662306a36Sopenharmony_ci		ce->ops->update_stats(ce);
58762306a36Sopenharmony_ci
58862306a36Sopenharmony_ci	total = ce->stats.runtime.total;
58962306a36Sopenharmony_ci	if (ce->ops->flags & COPS_RUNTIME_CYCLES)
59062306a36Sopenharmony_ci		total *= ce->engine->gt->clock_period_ns;
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	active = READ_ONCE(ce->stats.active);
59362306a36Sopenharmony_ci	if (active)
59462306a36Sopenharmony_ci		active = intel_context_clock() - active;
59562306a36Sopenharmony_ci
59662306a36Sopenharmony_ci	return total + active;
59762306a36Sopenharmony_ci}
59862306a36Sopenharmony_ci
59962306a36Sopenharmony_ciu64 intel_context_get_avg_runtime_ns(struct intel_context *ce)
60062306a36Sopenharmony_ci{
60162306a36Sopenharmony_ci	u64 avg = ewma_runtime_read(&ce->stats.runtime.avg);
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	if (ce->ops->flags & COPS_RUNTIME_CYCLES)
60462306a36Sopenharmony_ci		avg *= ce->engine->gt->clock_period_ns;
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return avg;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cibool intel_context_ban(struct intel_context *ce, struct i915_request *rq)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	bool ret = intel_context_set_banned(ce);
61262306a36Sopenharmony_ci
61362306a36Sopenharmony_ci	trace_intel_context_ban(ce);
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (ce->ops->revoke)
61662306a36Sopenharmony_ci		ce->ops->revoke(ce, rq,
61762306a36Sopenharmony_ci				INTEL_CONTEXT_BANNED_PREEMPT_TIMEOUT_MS);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	return ret;
62062306a36Sopenharmony_ci}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_cibool intel_context_revoke(struct intel_context *ce)
62362306a36Sopenharmony_ci{
62462306a36Sopenharmony_ci	bool ret = intel_context_set_exiting(ce);
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci	if (ce->ops->revoke)
62762306a36Sopenharmony_ci		ce->ops->revoke(ce, NULL, ce->engine->props.preempt_timeout_ms);
62862306a36Sopenharmony_ci
62962306a36Sopenharmony_ci	return ret;
63062306a36Sopenharmony_ci}
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci#if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)
63362306a36Sopenharmony_ci#include "selftest_context.c"
63462306a36Sopenharmony_ci#endif
635