diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 180d450a6deb..a489a8d73991 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -453,6 +453,19 @@ struct xe_device { struct mutex lock; } d3cold; + /** @pme: Encapsulate pme related stuff */ + struct { + /** @pme.capable: Indicates if device is PME capable */ + bool capable; + + /** @pme.enabled: + * + * Indicates if PME is enabled - depends on user controllable + * sysfs interface as well + */ + bool enabled; + } pme; + /** @pm_notifier: Our PM notifier to perform actions in response to various PM events. */ struct notifier_block pm_notifier; /** @pm_block: Completion to block validating tasks on suspend / hibernate prepare */ diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 1e04e8ef2611..b134d90c01a1 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -1380,6 +1380,8 @@ 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); + unsigned int flags; + bool pme_enabled; int err; /* @@ -1391,9 +1393,25 @@ static int xe_pci_runtime_suspend(struct device *dev) xe_assert(xe, !IS_SRIOV_VF(xe)); xe_assert(xe, !pci_num_vf(pdev)); + flags = memalloc_noreclaim_save(); + pme_enabled = xe->pme.capable && !xe->d3cold.allowed && + pci_enable_wake(pdev, PCI_D3hot, true) == 0; + memalloc_noreclaim_restore(flags); + + xe_pm_update_pme_enabled(xe, pme_enabled); + err = xe_pm_runtime_suspend(xe); - if (err) + if (err) { + if (pme_enabled) { + flags = memalloc_noreclaim_save(); + pci_enable_wake(pdev, PCI_D3hot, false); + memalloc_noreclaim_restore(flags); + + xe_pm_update_pme_enabled(xe, false); + } + return err; + } pci_save_state(pdev); @@ -1422,6 +1440,8 @@ static int xe_pci_runtime_resume(struct device *dev) pci_restore_state(pdev); + xe_pm_update_pme_enabled(xe, false); + if (xe->d3cold.allowed) { err = pci_enable_device(pdev); if (err) diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c index f517bf453b54..e71bb90c9b80 100644 --- a/drivers/gpu/drm/xe/xe_pm.c +++ b/drivers/gpu/drm/xe/xe_pm.c @@ -78,6 +78,8 @@ * management (RPS). */ +#define HAS_PM_PME_SUPPORT(xe) (GRAPHICS_VERx100(xe) >= 3500) + #ifdef CONFIG_LOCKDEP static struct lockdep_map xe_pm_runtime_d3cold_map = { .name = "xe_rpm_d3cold_map" @@ -384,6 +386,14 @@ int xe_pm_init_early(struct xe_device *xe) } ALLOW_ERROR_INJECTION(xe_pm_init_early, ERRNO); /* See xe_pci_probe() */ +static bool xe_pm_pci_pme_capable(struct xe_device *xe) +{ + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + + return HAS_PM_PME_SUPPORT(xe) ? + pci_pme_capable(pdev, PCI_D3hot) : false; +} + /** * xe_pm_probe() - Initialize Xe Power Management * @xe: the &xe_device instance @@ -397,6 +407,16 @@ int xe_pm_probe(struct xe_device *xe) xe->d3cold.capable = xe_pm_pci_d3cold_capable(xe); xe_dbg(xe, "d3cold: capable=%s\n", str_yes_no(xe->d3cold.capable)); + xe->pme.capable = xe_pm_pci_pme_capable(xe); + xe_dbg(xe, "pme: capable=%s\n", str_yes_no(xe->pme.capable)); + + if (xe->pme.capable) { + int err = devm_device_init_wakeup(xe->drm.dev); + + if (err) + return err; + } + return 0; } @@ -650,6 +670,7 @@ int xe_pm_runtime_suspend(struct xe_device *xe) return 0; out_resume: + xe_pm_update_pme_enabled(xe, false); xe_display_pm_runtime_resume(xe); xe_pxp_pm_resume(xe->pxp); out: @@ -993,6 +1014,30 @@ int xe_pm_set_vram_threshold(struct xe_device *xe, u32 threshold) return 0; } +/** + * xe_pm_pme_enabled - get the current status of PME enabled + * @xe: xe device instance + * + * Returns: True if PME is enabled, false otherwise. + */ +bool xe_pm_pme_enabled(struct xe_device *xe) +{ + return xe->pme.enabled; +} + +/** + * xe_pm_update_pme_enabled - Update the PME enabled state + * @xe: xe device instance + * @status: New PME enabled status + * + * Called during runtime suspend / resume. Status is set to True if PME is + * enabled during runtime_suspend. Cleared on runtime_resume. + */ +void xe_pm_update_pme_enabled(struct xe_device *xe, bool status) +{ + xe->pme.enabled = status; +} + /** * xe_pm_d3cold_allowed_toggle - Check conditions to toggle d3cold.allowed * @xe: xe device instance diff --git a/drivers/gpu/drm/xe/xe_pm.h b/drivers/gpu/drm/xe/xe_pm.h index 6d5ab09cb769..037c73ea4342 100644 --- a/drivers/gpu/drm/xe/xe_pm.h +++ b/drivers/gpu/drm/xe/xe_pm.h @@ -33,6 +33,8 @@ bool xe_pm_runtime_resume_and_get(struct xe_device *xe); void xe_pm_assert_unbounded_bridge(struct xe_device *xe); int xe_pm_set_vram_threshold(struct xe_device *xe, u32 threshold); void xe_pm_d3cold_allowed_toggle(struct xe_device *xe); +bool xe_pm_pme_enabled(struct xe_device *xe); +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);