[PATCH 4/7] drm/i915/guc: Don't hog IRQs when destroying contexts
John Harrison
john.c.harrison at intel.com
Sat Dec 11 01:07:12 UTC 2021
On 12/10/2021 16:56, Matthew Brost wrote:
> From: John Harrison <John.C.Harrison at Intel.com>
>
> While attempting to debug a CT deadlock issue in various CI failures
> (most easily reproduced with gem_ctx_create/basic-files), I was seeing
> CPU deadlock errors being reported. This were because the context
> destroy loop was blocking waiting on H2G space from inside an IRQ
> spinlock. There was deadlock as such, it's just that the H2G queue was
There was *no* deadlock as such
John.
> full of context destroy commands and GuC was taking a long time to
> process them. However, the kernel was seeing the large amount of time
> spent inside the IRQ lock as a dead CPU. Various Bad Things(tm) would
> then happen (heartbeat failures, CT deadlock errors, outstanding H2G
> WARNs, etc.).
>
> Re-working the loop to only acquire the spinlock around the list
> management (which is all it is meant to protect) rather than the
> entire destroy operation seems to fix all the above issues.
>
> Signed-off-by: John Harrison <John.C.Harrison at Intel.com>
> ---
> .../gpu/drm/i915/gt/uc/intel_guc_submission.c | 45 ++++++++++++-------
> 1 file changed, 28 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> index 36c2965db49b..96fcf869e3ff 100644
> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
> @@ -2644,7 +2644,6 @@ static inline void guc_lrc_desc_unpin(struct intel_context *ce)
> unsigned long flags;
> bool disabled;
>
> - lockdep_assert_held(&guc->submission_state.lock);
> GEM_BUG_ON(!intel_gt_pm_is_awake(gt));
> GEM_BUG_ON(!lrc_desc_registered(guc, ce->guc_id.id));
> GEM_BUG_ON(ce != __get_context(guc, ce->guc_id.id));
> @@ -2660,7 +2659,7 @@ static inline void guc_lrc_desc_unpin(struct intel_context *ce)
> }
> spin_unlock_irqrestore(&ce->guc_state.lock, flags);
> if (unlikely(disabled)) {
> - __release_guc_id(guc, ce);
> + release_guc_id(guc, ce);
> __guc_context_destroy(ce);
> return;
> }
> @@ -2694,36 +2693,48 @@ static void __guc_context_destroy(struct intel_context *ce)
>
> static void guc_flush_destroyed_contexts(struct intel_guc *guc)
> {
> - struct intel_context *ce, *cn;
> + struct intel_context *ce;
> unsigned long flags;
>
> GEM_BUG_ON(!submission_disabled(guc) &&
> guc_submission_initialized(guc));
>
> - spin_lock_irqsave(&guc->submission_state.lock, flags);
> - list_for_each_entry_safe(ce, cn,
> - &guc->submission_state.destroyed_contexts,
> - destroyed_link) {
> - list_del_init(&ce->destroyed_link);
> - __release_guc_id(guc, ce);
> + while (!list_empty(&guc->submission_state.destroyed_contexts)) {
> + spin_lock_irqsave(&guc->submission_state.lock, flags);
> + ce = list_first_entry_or_null(&guc->submission_state.destroyed_contexts,
> + struct intel_context,
> + destroyed_link);
> + if (ce)
> + list_del_init(&ce->destroyed_link);
> + spin_unlock_irqrestore(&guc->submission_state.lock, flags);
> +
> + if (!ce)
> + break;
> +
> + release_guc_id(guc, ce);
> __guc_context_destroy(ce);
> }
> - spin_unlock_irqrestore(&guc->submission_state.lock, flags);
> }
>
> static void deregister_destroyed_contexts(struct intel_guc *guc)
> {
> - struct intel_context *ce, *cn;
> + struct intel_context *ce;
> unsigned long flags;
>
> - spin_lock_irqsave(&guc->submission_state.lock, flags);
> - list_for_each_entry_safe(ce, cn,
> - &guc->submission_state.destroyed_contexts,
> - destroyed_link) {
> - list_del_init(&ce->destroyed_link);
> + while (!list_empty(&guc->submission_state.destroyed_contexts)) {
> + spin_lock_irqsave(&guc->submission_state.lock, flags);
> + ce = list_first_entry_or_null(&guc->submission_state.destroyed_contexts,
> + struct intel_context,
> + destroyed_link);
> + if (ce)
> + list_del_init(&ce->destroyed_link);
> + spin_unlock_irqrestore(&guc->submission_state.lock, flags);
> +
> + if (!ce)
> + break;
> +
> guc_lrc_desc_unpin(ce);
> }
> - spin_unlock_irqrestore(&guc->submission_state.lock, flags);
> }
>
> static void destroyed_worker_func(struct work_struct *w)
More information about the dri-devel
mailing list