mirror of
https://github.com/torvalds/linux.git
synced 2026-10-29 21:06:02 +01:00
drm/xe: Poll GT for C6 before D3
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> Link: https://patch.msgid.link/20260916190614.3047807-1-vinay.belgaumkar@intel.com Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
This commit is contained in:
parent
25a7255afb
commit
320662381c
|
|
@ -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 = >->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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_ */
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user