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 #include +#include #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 = >->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 00b2b5dfb8f6..d66d5a0339ae 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -1379,7 +1379,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 @@ -1394,6 +1394,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);