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