Intel-XE Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v6] drm/xe: Poll GT for C6 before D3
@ 2026-09-16 19:06 Vinay Belgaumkar
  2026-09-16 19:24 ` sashiko-bot
  2026-09-18 15:47 ` Rodrigo Vivi
  0 siblings, 2 replies; 5+ messages in thread
From: Vinay Belgaumkar @ 2026-09-16 19:06 UTC (permalink / raw)
  To: intel-xe; +Cc: Vinay Belgaumkar, Badal Nilawar, Rodrigo Vivi

Ensure GT C6 state before D3 transition in runtime suspend flow.
This avoids the scenario where GT is being accessed after D3 state
is programmed. If the check for C6 fails, resume the device so it is
not stuck in an intermediate state.

v2: Force resume when we cancel suspend due to C6 check (Sashiko)
v3: Abort the suspend properly when idle check fails (Sashiko)
v4: Only check for C6 during suspend (Rodrigo). Have check in
xe_pci_runtime_suspend() instead of xe_pci_suspend().
v5: Don't checkfor PVC (Sashiko), rename function from_device_c6
to _device_idle
v6: Rename to _wait_all_c6 and move PVC check to gt_idle (Rodrigo)

Cc: Badal Nilawar <badal.nilawar@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
---
 drivers/gpu/drm/xe/xe_gt_idle.c | 39 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_gt_idle.h |  1 +
 drivers/gpu/drm/xe/xe_pci.c     | 13 ++++++++++-
 drivers/gpu/drm/xe/xe_pm.c      | 18 +++++++++++++++
 drivers/gpu/drm/xe/xe_pm.h      |  1 +
 5 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_gt_idle.c b/drivers/gpu/drm/xe/xe_gt_idle.c
index c208d7563e36..2eefd62f8d59 100644
--- a/drivers/gpu/drm/xe/xe_gt_idle.c
+++ b/drivers/gpu/drm/xe/xe_gt_idle.c
@@ -8,10 +8,12 @@
 #include <drm/drm_managed.h>
 
 #include <generated/xe_wa_oob.h>
+#include <linux/iopoll.h>
 #include "xe_force_wake.h"
 #include "xe_device.h"
 #include "xe_gt.h"
 #include "xe_gt_idle.h"
+#include "xe_gt_printk.h"
 #include "xe_gt_sysfs.h"
 #include "xe_guc_pc.h"
 #include "regs/xe_gt_regs.h"
@@ -451,3 +453,40 @@ int xe_gt_idle_disable_c6(struct xe_gt *gt)
 
 	return 0;
 }
+
+static int wait_for_gt_c6_state(struct xe_gt *gt, u32 timeout_ms)
+{
+	struct xe_guc_pc *pc = &gt->uc.guc.pc;
+	enum xe_gt_idle_state state;
+
+	return poll_timeout_us(state = gt->gtidle.idle_status(pc),
+			       state == GT_IDLE_C6,
+			       20,
+			       timeout_ms * USEC_PER_MSEC,
+			       false);
+}
+
+/**
+ * xe_gt_idle_wait_for_c6 - Poll for GT C6
+ * @gt: GT object
+ * @timeout_ms: wait time in ms
+ *
+ * This function waits for GT to enter C6.
+ *
+ * Return: 0 on success, -EAGAIN otherwise
+ */
+int xe_gt_idle_wait_for_c6(struct xe_gt *gt, u32 timeout_ms)
+{
+	if (IS_SRIOV_VF(gt_to_xe(gt)))
+		return 0;
+
+	if (gt_to_xe(gt)->info.platform == XE_PVC)
+		return 0;
+
+	if (wait_for_gt_c6_state(gt, timeout_ms)) {
+		xe_gt_dbg(gt, "GT is not in C6\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/xe/xe_gt_idle.h b/drivers/gpu/drm/xe/xe_gt_idle.h
index 9c34a155e102..2c8e9adf4a68 100644
--- a/drivers/gpu/drm/xe/xe_gt_idle.h
+++ b/drivers/gpu/drm/xe/xe_gt_idle.h
@@ -18,5 +18,6 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt);
 void xe_gt_idle_disable_pg(struct xe_gt *gt);
 int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p);
 u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle);
+int xe_gt_idle_wait_for_c6(struct xe_gt *gt, u32 timeout_ms);
 
 #endif /* _XE_GT_IDLE_H_ */
diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
index ab4da1d9a9f1..1a1bae5b936d 100644
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@ -1381,7 +1381,7 @@ static int xe_pci_runtime_suspend(struct device *dev)
 {
 	struct pci_dev *pdev = to_pci_dev(dev);
 	struct xe_device *xe = pdev_to_xe_device(pdev);
-	int err;
+	int err, ret;
 
 	/*
 	 * We hold an additional reference to the runtime PM to keep PF in D0
@@ -1396,6 +1396,17 @@ static int xe_pci_runtime_suspend(struct device *dev)
 	if (err)
 		return err;
 
+	err = xe_pm_wait_all_c6(xe);
+	if (err) {
+		drm_dbg(&xe->drm, "Resuming - GT C6 check failed!");
+		ret = xe_pm_runtime_resume(xe);
+		if (ret) {
+			drm_err(&xe->drm, "Resume failed after suspend was canceled");
+			return ret;
+		}
+		return err;
+	}
+
 	pci_save_state(pdev);
 
 	if (xe->d3cold.allowed) {
diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c
index f517bf453b54..4a745c3a933b 100644
--- a/drivers/gpu/drm/xe/xe_pm.c
+++ b/drivers/gpu/drm/xe/xe_pm.c
@@ -1030,6 +1030,24 @@ void xe_pm_d3cold_allowed_toggle(struct xe_device *xe)
 	mutex_unlock(&xe->d3cold.lock);
 }
 
+/**
+ * xe_pm_wait_all_c6() - Wait for all GTs to enter C6.
+ * @xe: xe device instance
+ *
+ * Return: 0 on success, -EAGAIN on failure
+ */
+int xe_pm_wait_all_c6(struct xe_device *xe)
+{
+	struct xe_gt *gt;
+	u8 id;
+
+	for_each_gt(gt, xe, id)
+		if (xe_gt_idle_wait_for_c6(gt, 200))
+			return -EAGAIN;
+
+	return 0;
+}
+
 /**
  * xe_pm_module_init() - Perform xe_pm specific module initialization.
  *
diff --git a/drivers/gpu/drm/xe/xe_pm.h b/drivers/gpu/drm/xe/xe_pm.h
index 6d5ab09cb769..fd8b2eab5de9 100644
--- a/drivers/gpu/drm/xe/xe_pm.h
+++ b/drivers/gpu/drm/xe/xe_pm.h
@@ -36,6 +36,7 @@ void xe_pm_d3cold_allowed_toggle(struct xe_device *xe);
 bool xe_rpm_reclaim_safe(const struct xe_device *xe);
 struct task_struct *xe_pm_read_callback_task(struct xe_device *xe);
 int xe_pm_block_on_suspend(struct xe_device *xe);
+int xe_pm_wait_all_c6(struct xe_device *xe);
 void xe_pm_might_block_on_suspend(void);
 int xe_pm_module_init(void);
 
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v6] drm/xe: Poll GT for C6 before D3
  2026-09-16 19:06 [PATCH v6] drm/xe: Poll GT for C6 before D3 Vinay Belgaumkar
@ 2026-09-16 19:24 ` sashiko-bot
  2026-09-16 21:03   ` Belgaumkar, Vinay
  2026-09-18 15:47 ` Rodrigo Vivi
  1 sibling, 1 reply; 5+ messages in thread
From: sashiko-bot @ 2026-09-16 19:24 UTC (permalink / raw)
  To: Vinay Belgaumkar; +Cc: intel-xe

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] drm/xe: C6 poll after xe_pm_runtime_suspend() always fails breaking D3
- [Medium] pm: device stuck in RPM_ACTIVE when C6 check fails
--

commit d48ea91e20a44679b212e2b189bddfe7fa5220c9
Author: Vinay Belgaumkar <vinay.belgaumkar@intel.com>

drm/xe: Poll GT for C6 before D3

This commit ensures the GT is in C6 before transitioning to D3 during
runtime suspend, avoiding scenarios where GT is accessed after D3 is
programmed. It aborts the suspend by returning an error if the GT
fails to enter C6.

> diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
> index 00b2b5dfb8f6c..d66d5a0339ae3 100644
> --- a/drivers/gpu/drm/xe/xe_pci.c
> +++ b/drivers/gpu/drm/xe/xe_pci.c

[ ... ]

> @@ -1394,6 +1394,17 @@ static int xe_pci_runtime_suspend(struct device *dev)
>  	if (err)
>  		return err;
>  
> +	err = xe_pm_wait_all_c6(xe);

[Severity: High]
Since this check happens after xe_pm_runtime_suspend(), which already
called xe_gt_suspend() and explicitly disabled power gating (RC6), isn't
this guaranteed to fail and cause 200ms timeouts on every suspend attempt?

When the system attempts to enter D3cold runtime suspend, GuC is already
reset and power gating is disabled by the time we reach this check, so
the GT cannot enter C6 autonomously.

> +	if (err) {
> +		drm_dbg(&xe->drm, "Resuming - GT C6 check failed!");
> +		ret = xe_pm_runtime_resume(xe);
> +		if (ret) {
> +			drm_err(&xe->drm, "Resume failed after suspend was canceled");
> +			return ret;
> +		}
> +		return err;

[Severity: Medium]
When we return -EAGAIN to the PM core here to abort the suspend, shouldn't
we first update the last_busy timestamp by calling
pm_runtime_mark_last_busy(dev)?

Without it, the PM core's rpm_suspend() handles -EAGAIN by aborting suspend
but only re-arms the autosuspend timer if last_busy was updated. This causes
the autosuspend expiration time to evaluate to the past, preventing the timer
from being re-armed and leaving the device awake indefinitely in RPM_ACTIVE
until another explicit PM cycle occurs.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260916190614.3047807-1-vinay.belgaumkar@intel.com?part=1

^ permalink raw reply	[flat|nested] 5+ messages in thread

* [PATCH v6] drm/xe: Poll GT for C6 before D3
@ 2026-09-16 20:59 Vinay Belgaumkar
  0 siblings, 0 replies; 5+ messages in thread
From: Vinay Belgaumkar @ 2026-09-16 20:59 UTC (permalink / raw)
  To: intel-xe; +Cc: Vinay Belgaumkar, Badal Nilawar, Rodrigo Vivi

Ensure GT C6 state before D3 transition in runtime suspend flow.
This avoids the scenario where GT is being accessed after D3 state
is programmed. If the check for C6 fails, resume the device so it is
not stuck in an intermediate state.

v2: Force resume when we cancel suspend due to C6 check (Sashiko)
v3: Abort the suspend properly when idle check fails (Sashiko)
v4: Only check for C6 during suspend (Rodrigo). Have check in
xe_pci_runtime_suspend() instead of xe_pci_suspend().
v5: Don't checkfor PVC (Sashiko), rename function from_device_c6
to _device_idle
v6: Rename to _wait_all_c6 and move PVC check to gt_idle (Rodrigo).
Also, rebase.

Cc: Badal Nilawar <badal.nilawar@intel.com>
Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
---
 drivers/gpu/drm/xe/xe_gt_idle.c | 39 +++++++++++++++++++++++++++++++++
 drivers/gpu/drm/xe/xe_gt_idle.h |  1 +
 drivers/gpu/drm/xe/xe_pci.c     | 13 ++++++++++-
 drivers/gpu/drm/xe/xe_pm.c      | 18 +++++++++++++++
 drivers/gpu/drm/xe/xe_pm.h      |  1 +
 5 files changed, 71 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/xe/xe_gt_idle.c b/drivers/gpu/drm/xe/xe_gt_idle.c
index c208d7563e36..2eefd62f8d59 100644
--- a/drivers/gpu/drm/xe/xe_gt_idle.c
+++ b/drivers/gpu/drm/xe/xe_gt_idle.c
@@ -8,10 +8,12 @@
 #include <drm/drm_managed.h>
 
 #include <generated/xe_wa_oob.h>
+#include <linux/iopoll.h>
 #include "xe_force_wake.h"
 #include "xe_device.h"
 #include "xe_gt.h"
 #include "xe_gt_idle.h"
+#include "xe_gt_printk.h"
 #include "xe_gt_sysfs.h"
 #include "xe_guc_pc.h"
 #include "regs/xe_gt_regs.h"
@@ -451,3 +453,40 @@ int xe_gt_idle_disable_c6(struct xe_gt *gt)
 
 	return 0;
 }
+
+static int wait_for_gt_c6_state(struct xe_gt *gt, u32 timeout_ms)
+{
+	struct xe_guc_pc *pc = &gt->uc.guc.pc;
+	enum xe_gt_idle_state state;
+
+	return poll_timeout_us(state = gt->gtidle.idle_status(pc),
+			       state == GT_IDLE_C6,
+			       20,
+			       timeout_ms * USEC_PER_MSEC,
+			       false);
+}
+
+/**
+ * xe_gt_idle_wait_for_c6 - Poll for GT C6
+ * @gt: GT object
+ * @timeout_ms: wait time in ms
+ *
+ * This function waits for GT to enter C6.
+ *
+ * Return: 0 on success, -EAGAIN otherwise
+ */
+int xe_gt_idle_wait_for_c6(struct xe_gt *gt, u32 timeout_ms)
+{
+	if (IS_SRIOV_VF(gt_to_xe(gt)))
+		return 0;
+
+	if (gt_to_xe(gt)->info.platform == XE_PVC)
+		return 0;
+
+	if (wait_for_gt_c6_state(gt, timeout_ms)) {
+		xe_gt_dbg(gt, "GT is not in C6\n");
+		return -EAGAIN;
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/xe/xe_gt_idle.h b/drivers/gpu/drm/xe/xe_gt_idle.h
index 9c34a155e102..2c8e9adf4a68 100644
--- a/drivers/gpu/drm/xe/xe_gt_idle.h
+++ b/drivers/gpu/drm/xe/xe_gt_idle.h
@@ -18,5 +18,6 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt);
 void xe_gt_idle_disable_pg(struct xe_gt *gt);
 int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p);
 u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle);
+int xe_gt_idle_wait_for_c6(struct xe_gt *gt, u32 timeout_ms);
 
 #endif /* _XE_GT_IDLE_H_ */
diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
index d10633f74aa4..d64e873d9e71 100644
--- a/drivers/gpu/drm/xe/xe_pci.c
+++ b/drivers/gpu/drm/xe/xe_pci.c
@@ -1382,7 +1382,7 @@ static int xe_pci_runtime_suspend(struct device *dev)
 	struct xe_device *xe = pdev_to_xe_device(pdev);
 	unsigned int flags;
 	bool pme_enabled;
-	int err;
+	int err, ret;
 
 	/*
 	 * We hold an additional reference to the runtime PM to keep PF in D0
@@ -1413,6 +1413,17 @@ static int xe_pci_runtime_suspend(struct device *dev)
 		return err;
 	}
 
+	err = xe_pm_wait_all_c6(xe);
+	if (err) {
+		drm_dbg(&xe->drm, "Resuming - GT C6 check failed!");
+		ret = xe_pm_runtime_resume(xe);
+		if (ret) {
+			drm_err(&xe->drm, "Resume failed after suspend was canceled");
+			return ret;
+		}
+		return err;
+	}
+
 	pci_save_state(pdev);
 
 	if (xe->d3cold.allowed) {
diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c
index e71bb90c9b80..daa7ba2df317 100644
--- a/drivers/gpu/drm/xe/xe_pm.c
+++ b/drivers/gpu/drm/xe/xe_pm.c
@@ -1075,6 +1075,24 @@ void xe_pm_d3cold_allowed_toggle(struct xe_device *xe)
 	mutex_unlock(&xe->d3cold.lock);
 }
 
+/**
+ * xe_pm_wait_all_c6() - Wait for all GTs to enter C6.
+ * @xe: xe device instance
+ *
+ * Return: 0 on success, -EAGAIN on failure
+ */
+int xe_pm_wait_all_c6(struct xe_device *xe)
+{
+	struct xe_gt *gt;
+	u8 id;
+
+	for_each_gt(gt, xe, id)
+		if (xe_gt_idle_wait_for_c6(gt, 200))
+			return -EAGAIN;
+
+	return 0;
+}
+
 /**
  * xe_pm_module_init() - Perform xe_pm specific module initialization.
  *
diff --git a/drivers/gpu/drm/xe/xe_pm.h b/drivers/gpu/drm/xe/xe_pm.h
index 037c73ea4342..16d4e6c629f1 100644
--- a/drivers/gpu/drm/xe/xe_pm.h
+++ b/drivers/gpu/drm/xe/xe_pm.h
@@ -38,6 +38,7 @@ void xe_pm_update_pme_enabled(struct xe_device *xe, bool status);
 bool xe_rpm_reclaim_safe(const struct xe_device *xe);
 struct task_struct *xe_pm_read_callback_task(struct xe_device *xe);
 int xe_pm_block_on_suspend(struct xe_device *xe);
+int xe_pm_wait_all_c6(struct xe_device *xe);
 void xe_pm_might_block_on_suspend(void);
 int xe_pm_module_init(void);
 
-- 
2.38.1


^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [PATCH v6] drm/xe: Poll GT for C6 before D3
  2026-09-16 19:24 ` sashiko-bot
@ 2026-09-16 21:03   ` Belgaumkar, Vinay
  0 siblings, 0 replies; 5+ messages in thread
From: Belgaumkar, Vinay @ 2026-09-16 21:03 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: intel-xe


On 9/16/2026 12:24 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [High] drm/xe: C6 poll after xe_pm_runtime_suspend() always fails breaking D3
> - [Medium] pm: device stuck in RPM_ACTIVE when C6 check fails
> --
>
> commit d48ea91e20a44679b212e2b189bddfe7fa5220c9
> Author: Vinay Belgaumkar <vinay.belgaumkar@intel.com>
>
> drm/xe: Poll GT for C6 before D3
>
> This commit ensures the GT is in C6 before transitioning to D3 during
> runtime suspend, avoiding scenarios where GT is accessed after D3 is
> programmed. It aborts the suspend by returning an error if the GT
> fails to enter C6.
>
>> diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
>> index 00b2b5dfb8f6c..d66d5a0339ae3 100644
>> --- a/drivers/gpu/drm/xe/xe_pci.c
>> +++ b/drivers/gpu/drm/xe/xe_pci.c
> [ ... ]
>
>> @@ -1394,6 +1394,17 @@ static int xe_pci_runtime_suspend(struct device *dev)
>>   	if (err)
>>   		return err;
>>   
>> +	err = xe_pm_wait_all_c6(xe);
> [Severity: High]
> Since this check happens after xe_pm_runtime_suspend(), which already
> called xe_gt_suspend() and explicitly disabled power gating (RC6), isn't
> this guaranteed to fail and cause 200ms timeouts on every suspend attempt?
>
> When the system attempts to enter D3cold runtime suspend, GuC is already
> reset and power gating is disabled by the time we reach this check, so
> the GT cannot enter C6 autonomously.
Disabling power gating has no impact on C6. GT can enter C6 in spite of it.
>
>> +	if (err) {
>> +		drm_dbg(&xe->drm, "Resuming - GT C6 check failed!");
>> +		ret = xe_pm_runtime_resume(xe);
>> +		if (ret) {
>> +			drm_err(&xe->drm, "Resume failed after suspend was canceled");
>> +			return ret;
>> +		}
>> +		return err;
> [Severity: Medium]
> When we return -EAGAIN to the PM core here to abort the suspend, shouldn't
> we first update the last_busy timestamp by calling
> pm_runtime_mark_last_busy(dev)?
>
> Without it, the PM core's rpm_suspend() handles -EAGAIN by aborting suspend
> but only re-arms the autosuspend timer if last_busy was updated. This causes
> the autosuspend expiration time to evaluate to the past, preventing the timer
> from being re-armed and leaving the device awake indefinitely in RPM_ACTIVE
> until another explicit PM cycle occurs.
This has been discussed previously. The next pm ref get/put should 
re-arm and trigger the auto suspend timer.
>

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [PATCH v6] drm/xe: Poll GT for C6 before D3
  2026-09-16 19:06 [PATCH v6] drm/xe: Poll GT for C6 before D3 Vinay Belgaumkar
  2026-09-16 19:24 ` sashiko-bot
@ 2026-09-18 15:47 ` Rodrigo Vivi
  1 sibling, 0 replies; 5+ messages in thread
From: Rodrigo Vivi @ 2026-09-18 15:47 UTC (permalink / raw)
  To: Vinay Belgaumkar; +Cc: intel-xe, Badal Nilawar

On Wed, Sep 16, 2026 at 12:06:14PM -0700, Vinay Belgaumkar wrote:
> Ensure GT C6 state before D3 transition in runtime suspend flow.
> This avoids the scenario where GT is being accessed after D3 state
> is programmed. If the check for C6 fails, resume the device so it is
> not stuck in an intermediate state.
> 
> v2: Force resume when we cancel suspend due to C6 check (Sashiko)
> v3: Abort the suspend properly when idle check fails (Sashiko)
> v4: Only check for C6 during suspend (Rodrigo). Have check in
> xe_pci_runtime_suspend() instead of xe_pci_suspend().
> v5: Don't checkfor PVC (Sashiko), rename function from_device_c6
> to _device_idle
> v6: Rename to _wait_all_c6 and move PVC check to gt_idle (Rodrigo)
> 
> Cc: Badal Nilawar <badal.nilawar@intel.com>
> Cc: Rodrigo Vivi <rodrigo.vivi@intel.com>
> Signed-off-by: Vinay Belgaumkar <vinay.belgaumkar@intel.com>

Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

pushing soon. Thank you

> ---
>  drivers/gpu/drm/xe/xe_gt_idle.c | 39 +++++++++++++++++++++++++++++++++
>  drivers/gpu/drm/xe/xe_gt_idle.h |  1 +
>  drivers/gpu/drm/xe/xe_pci.c     | 13 ++++++++++-
>  drivers/gpu/drm/xe/xe_pm.c      | 18 +++++++++++++++
>  drivers/gpu/drm/xe/xe_pm.h      |  1 +
>  5 files changed, 71 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/xe/xe_gt_idle.c b/drivers/gpu/drm/xe/xe_gt_idle.c
> index c208d7563e36..2eefd62f8d59 100644
> --- a/drivers/gpu/drm/xe/xe_gt_idle.c
> +++ b/drivers/gpu/drm/xe/xe_gt_idle.c
> @@ -8,10 +8,12 @@
>  #include <drm/drm_managed.h>
>  
>  #include <generated/xe_wa_oob.h>
> +#include <linux/iopoll.h>
>  #include "xe_force_wake.h"
>  #include "xe_device.h"
>  #include "xe_gt.h"
>  #include "xe_gt_idle.h"
> +#include "xe_gt_printk.h"
>  #include "xe_gt_sysfs.h"
>  #include "xe_guc_pc.h"
>  #include "regs/xe_gt_regs.h"
> @@ -451,3 +453,40 @@ int xe_gt_idle_disable_c6(struct xe_gt *gt)
>  
>  	return 0;
>  }
> +
> +static int wait_for_gt_c6_state(struct xe_gt *gt, u32 timeout_ms)
> +{
> +	struct xe_guc_pc *pc = &gt->uc.guc.pc;
> +	enum xe_gt_idle_state state;
> +
> +	return poll_timeout_us(state = gt->gtidle.idle_status(pc),
> +			       state == GT_IDLE_C6,
> +			       20,
> +			       timeout_ms * USEC_PER_MSEC,
> +			       false);
> +}
> +
> +/**
> + * xe_gt_idle_wait_for_c6 - Poll for GT C6
> + * @gt: GT object
> + * @timeout_ms: wait time in ms
> + *
> + * This function waits for GT to enter C6.
> + *
> + * Return: 0 on success, -EAGAIN otherwise
> + */
> +int xe_gt_idle_wait_for_c6(struct xe_gt *gt, u32 timeout_ms)
> +{
> +	if (IS_SRIOV_VF(gt_to_xe(gt)))
> +		return 0;
> +
> +	if (gt_to_xe(gt)->info.platform == XE_PVC)
> +		return 0;
> +
> +	if (wait_for_gt_c6_state(gt, timeout_ms)) {
> +		xe_gt_dbg(gt, "GT is not in C6\n");
> +		return -EAGAIN;
> +	}
> +
> +	return 0;
> +}
> diff --git a/drivers/gpu/drm/xe/xe_gt_idle.h b/drivers/gpu/drm/xe/xe_gt_idle.h
> index 9c34a155e102..2c8e9adf4a68 100644
> --- a/drivers/gpu/drm/xe/xe_gt_idle.h
> +++ b/drivers/gpu/drm/xe/xe_gt_idle.h
> @@ -18,5 +18,6 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt);
>  void xe_gt_idle_disable_pg(struct xe_gt *gt);
>  int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p);
>  u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle);
> +int xe_gt_idle_wait_for_c6(struct xe_gt *gt, u32 timeout_ms);
>  
>  #endif /* _XE_GT_IDLE_H_ */
> diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c
> index ab4da1d9a9f1..1a1bae5b936d 100644
> --- a/drivers/gpu/drm/xe/xe_pci.c
> +++ b/drivers/gpu/drm/xe/xe_pci.c
> @@ -1381,7 +1381,7 @@ static int xe_pci_runtime_suspend(struct device *dev)
>  {
>  	struct pci_dev *pdev = to_pci_dev(dev);
>  	struct xe_device *xe = pdev_to_xe_device(pdev);
> -	int err;
> +	int err, ret;
>  
>  	/*
>  	 * We hold an additional reference to the runtime PM to keep PF in D0
> @@ -1396,6 +1396,17 @@ static int xe_pci_runtime_suspend(struct device *dev)
>  	if (err)
>  		return err;
>  
> +	err = xe_pm_wait_all_c6(xe);
> +	if (err) {
> +		drm_dbg(&xe->drm, "Resuming - GT C6 check failed!");
> +		ret = xe_pm_runtime_resume(xe);
> +		if (ret) {
> +			drm_err(&xe->drm, "Resume failed after suspend was canceled");
> +			return ret;
> +		}
> +		return err;
> +	}
> +
>  	pci_save_state(pdev);
>  
>  	if (xe->d3cold.allowed) {
> diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c
> index f517bf453b54..4a745c3a933b 100644
> --- a/drivers/gpu/drm/xe/xe_pm.c
> +++ b/drivers/gpu/drm/xe/xe_pm.c
> @@ -1030,6 +1030,24 @@ void xe_pm_d3cold_allowed_toggle(struct xe_device *xe)
>  	mutex_unlock(&xe->d3cold.lock);
>  }
>  
> +/**
> + * xe_pm_wait_all_c6() - Wait for all GTs to enter C6.
> + * @xe: xe device instance
> + *
> + * Return: 0 on success, -EAGAIN on failure
> + */
> +int xe_pm_wait_all_c6(struct xe_device *xe)
> +{
> +	struct xe_gt *gt;
> +	u8 id;
> +
> +	for_each_gt(gt, xe, id)
> +		if (xe_gt_idle_wait_for_c6(gt, 200))
> +			return -EAGAIN;
> +
> +	return 0;
> +}
> +
>  /**
>   * xe_pm_module_init() - Perform xe_pm specific module initialization.
>   *
> diff --git a/drivers/gpu/drm/xe/xe_pm.h b/drivers/gpu/drm/xe/xe_pm.h
> index 6d5ab09cb769..fd8b2eab5de9 100644
> --- a/drivers/gpu/drm/xe/xe_pm.h
> +++ b/drivers/gpu/drm/xe/xe_pm.h
> @@ -36,6 +36,7 @@ void xe_pm_d3cold_allowed_toggle(struct xe_device *xe);
>  bool xe_rpm_reclaim_safe(const struct xe_device *xe);
>  struct task_struct *xe_pm_read_callback_task(struct xe_device *xe);
>  int xe_pm_block_on_suspend(struct xe_device *xe);
> +int xe_pm_wait_all_c6(struct xe_device *xe);
>  void xe_pm_might_block_on_suspend(void);
>  int xe_pm_module_init(void);
>  
> -- 
> 2.38.1
> 

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2026-09-18 15:47 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-16 19:06 [PATCH v6] drm/xe: Poll GT for C6 before D3 Vinay Belgaumkar
2026-09-16 19:24 ` sashiko-bot
2026-09-16 21:03   ` Belgaumkar, Vinay
2026-09-18 15:47 ` Rodrigo Vivi
  -- strict thread matches above, loose matches on Subject: below --
2026-09-16 20:59 Vinay Belgaumkar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox