Intel-GFX Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Jani Nikula <jani.nikula@linux.intel.com>
To: Weifeng Liu <weifeng.liu.z@gmail.com>, intel-gfx@lists.freedesktop.org
Cc: matthew.brost@intel.com, joonas.lahtinen@linux.intel.com,
	rodrigo.vivi@intel.com, tursulin@ursulin.net,
	dri-devel@lists.freedesktop.org, weifeng.liu@intel.com
Subject: Re: [PATCH] drm/i915: Make suspend idle wait uninterruptible
Date: Wed, 12 Aug 2026 12:06:47 +0300	[thread overview]
Message-ID: <c0cc3364b35c8648df3ff407606cf13835eb449f@intel.com> (raw)
In-Reply-To: <ee7f26285f8ca8a8993f8cb62b4d893e4106b10c.camel@gmail.com>

On Wed, 12 Aug 2026, Weifeng Liu <weifeng.liu.z@gmail.com> wrote:
> Gentle ping. I would like to provide some additional context about the
> issue this patch is trying to fix.

Have you filed a bug over at [1]? If not, please do, and add the
information there, with logs, and point at this thread too.

Thanks,
Jani.


[1] https://drm.pages.freedesktop.org/intel-docs/how-to-file-i915-bugs.html




>
> A customer observed a shutdown hang in an automated S3 resume and
> power-off test. This issue occurs after resuming from S3 and later
> starting the power-off sequence. During process teardown, i915 reports
> GuC CT errors such as:
>
>   i915 0000:00:02.0: [drm] *ERROR* GT0: GUC: CT: Unsolicited response
> message: len 1, data 0xe0000100 (fence 2941, last 2945)
>   i915 0000:00:02.0: [drm] *ERROR* GT0: GUC: CT: Failed to handle HXG
> message (-ENOKEY) 00 01 00 e0
>   i915 0000:00:02.0: [drm] *ERROR* GT0: GUC: CT: Failed to process CT
> message (-ENOKEY) 01 00 7d 0b 00 01 00 e0
>
> No rendering or display failure was observed before shutdown. The GuC
> error appears to be related to inconsistent context state after S3, but
> this patch does not attempt to fix that underlying issue; I focused on
> fixing the shutdown hang issue currently.
>
> With initcall_debug enabled, the last device shutdown message is:
>
>   i915 0000:00:02.0: shutdown
>
> and device_shutdown() does not make further progress.
>
> While investigating this hang, I found that wait_for_suspend() assumes
> that intel_gt_wait_for_idle() either succeeds or returns -ETIME.
> However, the request retirement and GuC pending-message waits are
> interruptible and may return -EINTR or -ERESTARTSYS when the shutdown
> task has a pending signal. These errors bypass the existing wedge and
> cleanup path, after which wait_for_suspend() may block waiting for a GT
> wakeref that cannot be released.
>
> As a diagnostic experiment, adding a timeout to
> intel_wakeref_wait_for_idle() allowed the power-off sequence to
> complete consistently. I did not propose that approach upstream because
> continuing suspend with an active GT would weaken the existing suspend
> invariant.
>
> Instead, this patch makes only GT idle wait used by wait_for_suspend()
> uninterruptible. It retains the existing timeout and wedges the GT only
> if that timeout expires. All other intel_gt_wait_for_idle() callers
> remain interruptible.
>
> Does this approach look reasonable, or would you prefer a different way
> to prevent signals from bypassing the existing timeout recovery path?
>
> And I'll be very grateful if you can provide some hints about the root
> cause of the GuC error.
>
> Best regards,
> Weifeng
>
> On Wed, 2026-08-05 at 14:45 +0800, Weifeng Liu wrote:
>> wait_for_suspend() only handles -ETIME from the GT idle wait.
>> However,
>> the wait can also be interrupted by a pending signal while retiring
>> requests or waiting for GuC messages, e.g., during the reboot process
>> invoked by init. This skips the wedge and cleanup path and may leave
>> suspend waiting indefinitely for a leaked wakeref.
>> 
>> Make only the suspend idle wait uninterruptible while preserving its
>> existing timeout. Other callers remain interruptible, and the GT is
>> still wedged only when the timeout expires.
>> 
>> Cc: Matthew Brost <matthew.brost@intel.com>
>> Assisted-by: OpenCode:GPT-5.6-Sol
>> Signed-off-by: Weifeng Liu <weifeng.liu.z@gmail.com>
>> ---
>>  drivers/gpu/drm/i915/gt/intel_gt.c            | 24 +++++++++++++++--
>> --
>>  drivers/gpu/drm/i915/gt/intel_gt.h            |  1 +
>>  drivers/gpu/drm/i915/gt/intel_gt_pm.c         |  3 ++-
>>  drivers/gpu/drm/i915/gt/intel_gt_requests.c   |  8 ++++---
>>  drivers/gpu/drm/i915/gt/intel_gt_requests.h   | 13 ++++++++--
>>  drivers/gpu/drm/i915/gt/uc/intel_guc.h        |  3 ++-
>>  .../gpu/drm/i915/gt/uc/intel_guc_submission.c |  5 ++--
>>  drivers/gpu/drm/i915/gt/uc/intel_uc.h         |  6 +++--
>>  8 files changed, 47 insertions(+), 16 deletions(-)
>> 
>> diff --git a/drivers/gpu/drm/i915/gt/intel_gt.c
>> b/drivers/gpu/drm/i915/gt/intel_gt.c
>> index 5c7f862f7100..5eaa52f535d4 100644
>> --- a/drivers/gpu/drm/i915/gt/intel_gt.c
>> +++ b/drivers/gpu/drm/i915/gt/intel_gt.c
>> @@ -659,7 +659,9 @@ static void __intel_gt_disable(struct intel_gt
>> *gt)
>>  	GEM_BUG_ON(intel_gt_pm_is_awake(gt));
>>  }
>>  
>> -int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout)
>> +static int __intel_gt_wait_for_idle(struct intel_gt *gt,
>> +				    bool interruptible,
>> +				    long timeout)
>>  {
>>  	long remaining_timeout;
>>  
>> @@ -667,10 +669,11 @@ int intel_gt_wait_for_idle(struct intel_gt *gt,
>> long timeout)
>>  	if (!intel_gt_pm_is_awake(gt))
>>  		return 0;
>>  
>> -	while ((timeout = intel_gt_retire_requests_timeout(gt,
>> timeout,
>> -							  
>> &remaining_timeout)) > 0) {
>> +	while ((timeout = __intel_gt_retire_requests_timeout(gt,
>> interruptible,
>> +							    
>> timeout,
>> +							    
>> &remaining_timeout)) > 0) {
>>  		cond_resched();
>> -		if (signal_pending(current))
>> +		if (interruptible && signal_pending(current))
>>  			return -EINTR;
>>  	}
>>  
>> @@ -680,7 +683,18 @@ int intel_gt_wait_for_idle(struct intel_gt *gt,
>> long timeout)
>>  	if (remaining_timeout < 0)
>>  		remaining_timeout = 0;
>>  
>> -	return intel_uc_wait_for_idle(&gt->uc, remaining_timeout);
>> +	return intel_uc_wait_for_idle(&gt->uc, interruptible,
>> +				      remaining_timeout);
>> +}
>> +
>> +int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout)
>> +{
>> +	return __intel_gt_wait_for_idle(gt, true, timeout);
>> +}
>> +
>> +int intel_gt_wait_for_idle_uninterruptible(struct intel_gt *gt, long
>> timeout)
>> +{
>> +	return __intel_gt_wait_for_idle(gt, false, timeout);
>>  }
>>  
>>  int intel_gt_init(struct intel_gt *gt)
>> diff --git a/drivers/gpu/drm/i915/gt/intel_gt.h
>> b/drivers/gpu/drm/i915/gt/intel_gt.h
>> index 998ca029b73a..6c7e5415f1dc 100644
>> --- a/drivers/gpu/drm/i915/gt/intel_gt.h
>> +++ b/drivers/gpu/drm/i915/gt/intel_gt.h
>> @@ -143,6 +143,7 @@ void intel_gt_driver_release(struct intel_gt
>> *gt);
>>  void intel_gt_driver_late_release_all(struct drm_i915_private
>> *i915);
>>  
>>  int intel_gt_wait_for_idle(struct intel_gt *gt, long timeout);
>> +int intel_gt_wait_for_idle_uninterruptible(struct intel_gt *gt, long
>> timeout);
>>  
>>  void intel_gt_check_and_clear_faults(struct intel_gt *gt);
>>  i915_reg_t intel_gt_perf_limit_reasons_reg(struct intel_gt *gt);
>> diff --git a/drivers/gpu/drm/i915/gt/intel_gt_pm.c
>> b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
>> index c7f59d60fac6..9fe31aa07ae8 100644
>> --- a/drivers/gpu/drm/i915/gt/intel_gt_pm.c
>> +++ b/drivers/gpu/drm/i915/gt/intel_gt_pm.c
>> @@ -315,7 +315,8 @@ static void wait_for_suspend(struct intel_gt *gt)
>>  	if (!intel_gt_pm_is_awake(gt))
>>  		return;
>>  
>> -	if (intel_gt_wait_for_idle(gt, I915_GT_SUSPEND_IDLE_TIMEOUT)
>> == -ETIME) {
>> +	if (intel_gt_wait_for_idle_uninterruptible(gt,
>> +						  
>> I915_GT_SUSPEND_IDLE_TIMEOUT) == -ETIME) {
>>  		/*
>>  		 * Forcibly cancel outstanding work and leave
>>  		 * the gpu quiet.
>> diff --git a/drivers/gpu/drm/i915/gt/intel_gt_requests.c
>> b/drivers/gpu/drm/i915/gt/intel_gt_requests.c
>> index 93298820bee2..b37e8f1d0b5c 100644
>> --- a/drivers/gpu/drm/i915/gt/intel_gt_requests.c
>> +++ b/drivers/gpu/drm/i915/gt/intel_gt_requests.c
>> @@ -130,8 +130,10 @@ void intel_engine_fini_retire(struct
>> intel_engine_cs *engine)
>>  	GEM_BUG_ON(engine->retire);
>>  }
>>  
>> -long intel_gt_retire_requests_timeout(struct intel_gt *gt, long
>> timeout,
>> -				      long *remaining_timeout)
>> +long __intel_gt_retire_requests_timeout(struct intel_gt *gt,
>> +					bool interruptible,
>> +					long timeout,
>> +					long *remaining_timeout)
>>  {
>>  	struct intel_gt_timelines *timelines = &gt->timelines;
>>  	struct intel_timeline *tl, *tn;
>> @@ -159,7 +161,7 @@ long intel_gt_retire_requests_timeout(struct
>> intel_gt *gt, long timeout,
>>  				mutex_unlock(&tl->mutex);
>>  
>>  				timeout =
>> dma_fence_wait_timeout(fence,
>> -								
>> true,
>> +								
>> interruptible,
>>  								
>> timeout);
>>  				dma_fence_put(fence);
>>  
>> diff --git a/drivers/gpu/drm/i915/gt/intel_gt_requests.h
>> b/drivers/gpu/drm/i915/gt/intel_gt_requests.h
>> index d2969f68dd64..9242f85f4040 100644
>> --- a/drivers/gpu/drm/i915/gt/intel_gt_requests.h
>> +++ b/drivers/gpu/drm/i915/gt/intel_gt_requests.h
>> @@ -12,8 +12,17 @@ struct intel_engine_cs;
>>  struct intel_gt;
>>  struct intel_timeline;
>>  
>> -long intel_gt_retire_requests_timeout(struct intel_gt *gt, long
>> timeout,
>> -				      long *remaining_timeout);
>> +long __intel_gt_retire_requests_timeout(struct intel_gt *gt,
>> +					bool interruptible,
>> +					long timeout,
>> +					long *remaining_timeout);
>> +static inline long
>> +intel_gt_retire_requests_timeout(struct intel_gt *gt, long timeout,
>> +				 long *remaining_timeout)
>> +{
>> +	return __intel_gt_retire_requests_timeout(gt, true, timeout,
>> +						   
>> remaining_timeout);
>> +}
>>  static inline void intel_gt_retire_requests(struct intel_gt *gt)
>>  {
>>  	intel_gt_retire_requests_timeout(gt, 0, NULL);
>> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
>> b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
>> index 053780f562c1..b5f4fddf5c1d 100644
>> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc.h
>> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc.h
>> @@ -509,7 +509,8 @@ static inline void intel_guc_disable_msg(struct
>> intel_guc *guc, u32 mask)
>>  	spin_unlock_irq(&guc->irq_lock);
>>  }
>>  
>> -int intel_guc_wait_for_idle(struct intel_guc *guc, long timeout);
>> +int intel_guc_wait_for_idle(struct intel_guc *guc, bool
>> interruptible,
>> +			    long timeout);
>>  
>>  int intel_guc_deregister_done_process_msg(struct intel_guc *guc,
>>  					  const u32 *msg, u32 len);
>> 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 788e59cdfac9..aa74208c2b4e 100644
>> --- a/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
>> +++ b/drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
>> @@ -680,14 +680,15 @@ int intel_guc_wait_for_pending_msg(struct
>> intel_guc *guc,
>>  	return (timeout < 0) ? timeout : 0;
>>  }
>>  
>> -int intel_guc_wait_for_idle(struct intel_guc *guc, long timeout)
>> +int intel_guc_wait_for_idle(struct intel_guc *guc, bool
>> interruptible,
>> +			    long timeout)
>>  {
>>  	if (!intel_uc_uses_guc_submission(&guc_to_gt(guc)->uc))
>>  		return 0;
>>  
>>  	return intel_guc_wait_for_pending_msg(guc,
>>  					      &guc-
>> >outstanding_submission_g2h,
>> -					      true, timeout);
>> +					      interruptible,
>> timeout);
>>  }
>>  
>>  static int guc_context_policy_init_v70(struct intel_context *ce,
>> bool loop);
>> diff --git a/drivers/gpu/drm/i915/gt/uc/intel_uc.h
>> b/drivers/gpu/drm/i915/gt/uc/intel_uc.h
>> index 014bb7d83689..b62fe3b96b64 100644
>> --- a/drivers/gpu/drm/i915/gt/uc/intel_uc.h
>> +++ b/drivers/gpu/drm/i915/gt/uc/intel_uc.h
>> @@ -96,9 +96,11 @@ uc_state_checkers(gsc, gsc_uc);
>>  #undef uc_state_checkers
>>  #undef __uc_state_checker
>>  
>> -static inline int intel_uc_wait_for_idle(struct intel_uc *uc, long
>> timeout)
>> +static inline int intel_uc_wait_for_idle(struct intel_uc *uc,
>> +					 bool interruptible,
>> +					 long timeout)
>>  {
>> -	return intel_guc_wait_for_idle(&uc->guc, timeout);
>> +	return intel_guc_wait_for_idle(&uc->guc, interruptible,
>> timeout);
>>  }
>>  
>>  #define intel_uc_ops_function(_NAME, _OPS, _TYPE, _RET) \

-- 
Jani Nikula, Intel

      reply	other threads:[~2026-08-12  9:06 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-05  6:45 [PATCH] drm/i915: Make suspend idle wait uninterruptible Weifeng Liu
2026-08-05  7:05 ` ✗ LGCI.VerificationFailed: failure for " Patchwork
2026-08-12  3:07 ` [PATCH] " Weifeng Liu
2026-08-12  9:06   ` Jani Nikula [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=c0cc3364b35c8648df3ff407606cf13835eb449f@intel.com \
    --to=jani.nikula@linux.intel.com \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=intel-gfx@lists.freedesktop.org \
    --cc=joonas.lahtinen@linux.intel.com \
    --cc=matthew.brost@intel.com \
    --cc=rodrigo.vivi@intel.com \
    --cc=tursulin@ursulin.net \
    --cc=weifeng.liu.z@gmail.com \
    --cc=weifeng.liu@intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox