1dd08ebf6SMatthew Brost // SPDX-License-Identifier: MIT 2dd08ebf6SMatthew Brost /* 3dd08ebf6SMatthew Brost * Copyright © 2022 Intel Corporation 4dd08ebf6SMatthew Brost */ 5dd08ebf6SMatthew Brost 6ea9f879dSLucas De Marchi #include "xe_pm.h" 7ea9f879dSLucas De Marchi 8dd08ebf6SMatthew Brost #include <linux/pm_runtime.h> 9dd08ebf6SMatthew Brost 10b2d75619SAnshuman Gupta #include <drm/drm_managed.h> 11dd08ebf6SMatthew Brost #include <drm/ttm/ttm_placement.h> 12dd08ebf6SMatthew Brost 131e5a4dfeSJani Nikula #include "display/xe_display.h" 14dd08ebf6SMatthew Brost #include "xe_bo.h" 15dd08ebf6SMatthew Brost #include "xe_bo_evict.h" 16dd08ebf6SMatthew Brost #include "xe_device.h" 17b2d75619SAnshuman Gupta #include "xe_device_sysfs.h" 18dd08ebf6SMatthew Brost #include "xe_ggtt.h" 19ea9f879dSLucas De Marchi #include "xe_gt.h" 2009d88e3bSAnshuman Gupta #include "xe_guc.h" 21dd08ebf6SMatthew Brost #include "xe_irq.h" 22dd08ebf6SMatthew Brost #include "xe_pcode.h" 23275aa53fSNirmoy Das #include "xe_trace.h" 240d053475SMatt Roper #include "xe_wa.h" 25dd08ebf6SMatthew Brost 26dd08ebf6SMatthew Brost /** 27dd08ebf6SMatthew Brost * DOC: Xe Power Management 28dd08ebf6SMatthew Brost * 2930c39952SRodrigo Vivi * Xe PM implements the main routines for both system level suspend states and 3030c39952SRodrigo Vivi * for the opportunistic runtime suspend states. 31dd08ebf6SMatthew Brost * 3230c39952SRodrigo Vivi * System Level Suspend (S-States) - In general this is OS initiated suspend 3330c39952SRodrigo Vivi * driven by ACPI for achieving S0ix (a.k.a. S2idle, freeze), S3 (suspend to ram), 3430c39952SRodrigo Vivi * S4 (disk). The main functions here are `xe_pm_suspend` and `xe_pm_resume`. They 3530c39952SRodrigo Vivi * are the main point for the suspend to and resume from these states. 36dd08ebf6SMatthew Brost * 3730c39952SRodrigo Vivi * PCI Device Suspend (D-States) - This is the opportunistic PCIe device low power 3830c39952SRodrigo Vivi * state D3, controlled by the PCI subsystem and ACPI with the help from the 3930c39952SRodrigo Vivi * runtime_pm infrastructure. 4030c39952SRodrigo Vivi * PCI D3 is special and can mean D3hot, where Vcc power is on for keeping memory 4130c39952SRodrigo Vivi * alive and quicker low latency resume or D3Cold where Vcc power is off for 4230c39952SRodrigo Vivi * better power savings. 4330c39952SRodrigo Vivi * The Vcc control of PCI hierarchy can only be controlled at the PCI root port 4430c39952SRodrigo Vivi * level, while the device driver can be behind multiple bridges/switches and 4530c39952SRodrigo Vivi * paired with other devices. For this reason, the PCI subsystem cannot perform 4630c39952SRodrigo Vivi * the transition towards D3Cold. The lowest runtime PM possible from the PCI 4730c39952SRodrigo Vivi * subsystem is D3hot. Then, if all these paired devices in the same root port 4830c39952SRodrigo Vivi * are in D3hot, ACPI will assist here and run its own methods (_PR3 and _OFF) 4930c39952SRodrigo Vivi * to perform the transition from D3hot to D3cold. Xe may disallow this 5030c39952SRodrigo Vivi * transition by calling pci_d3cold_disable(root_pdev) before going to runtime 5130c39952SRodrigo Vivi * suspend. It will be based on runtime conditions such as VRAM usage for a 5230c39952SRodrigo Vivi * quick and low latency resume for instance. 53dd08ebf6SMatthew Brost * 5430c39952SRodrigo Vivi * Runtime PM - This infrastructure provided by the Linux kernel allows the 5530c39952SRodrigo Vivi * device drivers to indicate when the can be runtime suspended, so the device 5630c39952SRodrigo Vivi * could be put at D3 (if supported), or allow deeper package sleep states 5730c39952SRodrigo Vivi * (PC-states), and/or other low level power states. Xe PM component provides 5830c39952SRodrigo Vivi * `xe_pm_runtime_suspend` and `xe_pm_runtime_resume` functions that PCI 5930c39952SRodrigo Vivi * subsystem will call before transition to/from runtime suspend. 60dd08ebf6SMatthew Brost * 6130c39952SRodrigo Vivi * Also, Xe PM provides get and put functions that Xe driver will use to 6230c39952SRodrigo Vivi * indicate activity. In order to avoid locking complications with the memory 6330c39952SRodrigo Vivi * management, whenever possible, these get and put functions needs to be called 6430c39952SRodrigo Vivi * from the higher/outer levels. 6530c39952SRodrigo Vivi * The main cases that need to be protected from the outer levels are: IOCTL, 6630c39952SRodrigo Vivi * sysfs, debugfs, dma-buf sharing, GPU execution. 6730c39952SRodrigo Vivi * 6830c39952SRodrigo Vivi * This component is not responsible for GT idleness (RC6) nor GT frequency 6930c39952SRodrigo Vivi * management (RPS). 70dd08ebf6SMatthew Brost */ 71dd08ebf6SMatthew Brost 728ae84a27SRodrigo Vivi #ifdef CONFIG_LOCKDEP 73379cad69SThomas Hellström static struct lockdep_map xe_pm_runtime_d3cold_map = { 74379cad69SThomas Hellström .name = "xe_rpm_d3cold_map" 75379cad69SThomas Hellström }; 76379cad69SThomas Hellström 77379cad69SThomas Hellström static struct lockdep_map xe_pm_runtime_nod3cold_map = { 78379cad69SThomas Hellström .name = "xe_rpm_nod3cold_map" 798ae84a27SRodrigo Vivi }; 808ae84a27SRodrigo Vivi #endif 818ae84a27SRodrigo Vivi 8234bb7b81SThomas Hellström /** 8334bb7b81SThomas Hellström * xe_rpm_reclaim_safe() - Whether runtime resume can be done from reclaim context 8434bb7b81SThomas Hellström * @xe: The xe device. 8534bb7b81SThomas Hellström * 8634bb7b81SThomas Hellström * Return: true if it is safe to runtime resume from reclaim context. 8734bb7b81SThomas Hellström * false otherwise. 8834bb7b81SThomas Hellström */ 8934bb7b81SThomas Hellström bool xe_rpm_reclaim_safe(const struct xe_device *xe) 90379cad69SThomas Hellström { 91379cad69SThomas Hellström return !xe->d3cold.capable && !xe->info.has_sriov; 92379cad69SThomas Hellström } 93379cad69SThomas Hellström 94379cad69SThomas Hellström static void xe_rpm_lockmap_acquire(const struct xe_device *xe) 95379cad69SThomas Hellström { 96379cad69SThomas Hellström lock_map_acquire(xe_rpm_reclaim_safe(xe) ? 97379cad69SThomas Hellström &xe_pm_runtime_nod3cold_map : 98379cad69SThomas Hellström &xe_pm_runtime_d3cold_map); 99379cad69SThomas Hellström } 100379cad69SThomas Hellström 101379cad69SThomas Hellström static void xe_rpm_lockmap_release(const struct xe_device *xe) 102379cad69SThomas Hellström { 103379cad69SThomas Hellström lock_map_release(xe_rpm_reclaim_safe(xe) ? 104379cad69SThomas Hellström &xe_pm_runtime_nod3cold_map : 105379cad69SThomas Hellström &xe_pm_runtime_d3cold_map); 106379cad69SThomas Hellström } 107379cad69SThomas Hellström 108dd08ebf6SMatthew Brost /** 109dd08ebf6SMatthew Brost * xe_pm_suspend - Helper for System suspend, i.e. S0->S3 / S0->S2idle 110dd08ebf6SMatthew Brost * @xe: xe device instance 111dd08ebf6SMatthew Brost * 112dd08ebf6SMatthew Brost * Return: 0 on success 113dd08ebf6SMatthew Brost */ 114dd08ebf6SMatthew Brost int xe_pm_suspend(struct xe_device *xe) 115dd08ebf6SMatthew Brost { 116dd08ebf6SMatthew Brost struct xe_gt *gt; 117dd08ebf6SMatthew Brost u8 id; 118dd08ebf6SMatthew Brost int err; 119dd08ebf6SMatthew Brost 120f7f24b79SRodrigo Vivi drm_dbg(&xe->drm, "Suspending device\n"); 121275aa53fSNirmoy Das trace_xe_pm_suspend(xe, __builtin_return_address(0)); 122f7f24b79SRodrigo Vivi 123dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) 124dd08ebf6SMatthew Brost xe_gt_suspend_prepare(gt); 125dd08ebf6SMatthew Brost 126cb8f81c1SMaarten Lankhorst xe_display_pm_suspend(xe, false); 127cb8f81c1SMaarten Lankhorst 128dd08ebf6SMatthew Brost /* FIXME: Super racey... */ 129dd08ebf6SMatthew Brost err = xe_bo_evict_all(xe); 130dd08ebf6SMatthew Brost if (err) 131f7f24b79SRodrigo Vivi goto err; 132dd08ebf6SMatthew Brost 133dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 134dd08ebf6SMatthew Brost err = xe_gt_suspend(gt); 13544e69495SMaarten Lankhorst if (err) { 136e7b180b2SRodrigo Vivi xe_display_pm_resume(xe, false); 137f7f24b79SRodrigo Vivi goto err; 138dd08ebf6SMatthew Brost } 13944e69495SMaarten Lankhorst } 140dd08ebf6SMatthew Brost 141dd08ebf6SMatthew Brost xe_irq_suspend(xe); 142dd08ebf6SMatthew Brost 14344e69495SMaarten Lankhorst xe_display_pm_suspend_late(xe); 14444e69495SMaarten Lankhorst 145f7f24b79SRodrigo Vivi drm_dbg(&xe->drm, "Device suspended\n"); 146dd08ebf6SMatthew Brost return 0; 147f7f24b79SRodrigo Vivi err: 148f7f24b79SRodrigo Vivi drm_dbg(&xe->drm, "Device suspend failed %d\n", err); 149f7f24b79SRodrigo Vivi return err; 150dd08ebf6SMatthew Brost } 151dd08ebf6SMatthew Brost 152dd08ebf6SMatthew Brost /** 153dd08ebf6SMatthew Brost * xe_pm_resume - Helper for System resume S3->S0 / S2idle->S0 154dd08ebf6SMatthew Brost * @xe: xe device instance 155dd08ebf6SMatthew Brost * 156dd08ebf6SMatthew Brost * Return: 0 on success 157dd08ebf6SMatthew Brost */ 158dd08ebf6SMatthew Brost int xe_pm_resume(struct xe_device *xe) 159dd08ebf6SMatthew Brost { 1600d053475SMatt Roper struct xe_tile *tile; 161dd08ebf6SMatthew Brost struct xe_gt *gt; 162dd08ebf6SMatthew Brost u8 id; 163dd08ebf6SMatthew Brost int err; 164dd08ebf6SMatthew Brost 165f7f24b79SRodrigo Vivi drm_dbg(&xe->drm, "Resuming device\n"); 166275aa53fSNirmoy Das trace_xe_pm_resume(xe, __builtin_return_address(0)); 167f7f24b79SRodrigo Vivi 1680d053475SMatt Roper for_each_tile(tile, xe, id) 1690d053475SMatt Roper xe_wa_apply_tile_workarounds(tile); 1700d053475SMatt Roper 171933fd5ffSRiana Tauro err = xe_pcode_ready(xe, true); 172dd08ebf6SMatthew Brost if (err) 173933fd5ffSRiana Tauro return err; 174dd08ebf6SMatthew Brost 17544e69495SMaarten Lankhorst xe_display_pm_resume_early(xe); 17644e69495SMaarten Lankhorst 177dd08ebf6SMatthew Brost /* 178dd08ebf6SMatthew Brost * This only restores pinned memory which is the memory required for the 179dd08ebf6SMatthew Brost * GT(s) to resume. 180dd08ebf6SMatthew Brost */ 181dd08ebf6SMatthew Brost err = xe_bo_restore_kernel(xe); 182dd08ebf6SMatthew Brost if (err) 183f7f24b79SRodrigo Vivi goto err; 184dd08ebf6SMatthew Brost 185dd08ebf6SMatthew Brost xe_irq_resume(xe); 186dd08ebf6SMatthew Brost 187dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) 188dd08ebf6SMatthew Brost xe_gt_resume(gt); 189dd08ebf6SMatthew Brost 190cb8f81c1SMaarten Lankhorst xe_display_pm_resume(xe, false); 191cb8f81c1SMaarten Lankhorst 192dd08ebf6SMatthew Brost err = xe_bo_restore_user(xe); 193dd08ebf6SMatthew Brost if (err) 194f7f24b79SRodrigo Vivi goto err; 195dd08ebf6SMatthew Brost 196f7f24b79SRodrigo Vivi drm_dbg(&xe->drm, "Device resumed\n"); 197dd08ebf6SMatthew Brost return 0; 198f7f24b79SRodrigo Vivi err: 199f7f24b79SRodrigo Vivi drm_dbg(&xe->drm, "Device resume failed %d\n", err); 200f7f24b79SRodrigo Vivi return err; 201dd08ebf6SMatthew Brost } 202dd08ebf6SMatthew Brost 20395ec8c1dSRiana Tauro static bool xe_pm_pci_d3cold_capable(struct xe_device *xe) 204ac0be3b5SAnshuman Gupta { 20595ec8c1dSRiana Tauro struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 206ac0be3b5SAnshuman Gupta struct pci_dev *root_pdev; 207ac0be3b5SAnshuman Gupta 208ac0be3b5SAnshuman Gupta root_pdev = pcie_find_root_port(pdev); 209ac0be3b5SAnshuman Gupta if (!root_pdev) 210ac0be3b5SAnshuman Gupta return false; 211ac0be3b5SAnshuman Gupta 21295ec8c1dSRiana Tauro /* D3Cold requires PME capability */ 21395ec8c1dSRiana Tauro if (!pci_pme_capable(root_pdev, PCI_D3cold)) { 21495ec8c1dSRiana Tauro drm_dbg(&xe->drm, "d3cold: PME# not supported\n"); 215ac0be3b5SAnshuman Gupta return false; 21695ec8c1dSRiana Tauro } 21795ec8c1dSRiana Tauro 21895ec8c1dSRiana Tauro /* D3Cold requires _PR3 power resource */ 21995ec8c1dSRiana Tauro if (!pci_pr3_present(root_pdev)) { 22095ec8c1dSRiana Tauro drm_dbg(&xe->drm, "d3cold: ACPI _PR3 not present\n"); 22195ec8c1dSRiana Tauro return false; 22295ec8c1dSRiana Tauro } 223ac0be3b5SAnshuman Gupta 224ac0be3b5SAnshuman Gupta return true; 225ac0be3b5SAnshuman Gupta } 226ac0be3b5SAnshuman Gupta 227fddebcbfSAnshuman Gupta static void xe_pm_runtime_init(struct xe_device *xe) 228dd08ebf6SMatthew Brost { 229dd08ebf6SMatthew Brost struct device *dev = xe->drm.dev; 230dd08ebf6SMatthew Brost 231d87c424aSRodrigo Vivi /* 232d87c424aSRodrigo Vivi * Disable the system suspend direct complete optimization. 233d87c424aSRodrigo Vivi * We need to ensure that the regular device suspend/resume functions 234d87c424aSRodrigo Vivi * are called since our runtime_pm cannot guarantee local memory 235d87c424aSRodrigo Vivi * eviction for d3cold. 236d87c424aSRodrigo Vivi * TODO: Check HDA audio dependencies claimed by i915, and then enforce 237d87c424aSRodrigo Vivi * this option to integrated graphics as well. 238d87c424aSRodrigo Vivi */ 239d87c424aSRodrigo Vivi if (IS_DGFX(xe)) 240d87c424aSRodrigo Vivi dev_pm_set_driver_flags(dev, DPM_FLAG_NO_DIRECT_COMPLETE); 241d87c424aSRodrigo Vivi 242dd08ebf6SMatthew Brost pm_runtime_use_autosuspend(dev); 243dd08ebf6SMatthew Brost pm_runtime_set_autosuspend_delay(dev, 1000); 244dd08ebf6SMatthew Brost pm_runtime_set_active(dev); 245dd08ebf6SMatthew Brost pm_runtime_allow(dev); 246dd08ebf6SMatthew Brost pm_runtime_mark_last_busy(dev); 247bba2ec41SRodrigo Vivi pm_runtime_put(dev); 248dd08ebf6SMatthew Brost } 249dd08ebf6SMatthew Brost 250c086bfc6SHimal Prasad Ghimiray int xe_pm_init_early(struct xe_device *xe) 251fa78e188SBadal Nilawar { 252c086bfc6SHimal Prasad Ghimiray int err; 253c086bfc6SHimal Prasad Ghimiray 254fa78e188SBadal Nilawar INIT_LIST_HEAD(&xe->mem_access.vram_userfault.list); 255c086bfc6SHimal Prasad Ghimiray 256c086bfc6SHimal Prasad Ghimiray err = drmm_mutex_init(&xe->drm, &xe->mem_access.vram_userfault.lock); 257c086bfc6SHimal Prasad Ghimiray if (err) 258c086bfc6SHimal Prasad Ghimiray return err; 259c086bfc6SHimal Prasad Ghimiray 260c086bfc6SHimal Prasad Ghimiray err = drmm_mutex_init(&xe->drm, &xe->d3cold.lock); 261c086bfc6SHimal Prasad Ghimiray if (err) 262c086bfc6SHimal Prasad Ghimiray return err; 263c086bfc6SHimal Prasad Ghimiray 264c086bfc6SHimal Prasad Ghimiray return 0; 265fa78e188SBadal Nilawar } 266fa78e188SBadal Nilawar 26730c39952SRodrigo Vivi /** 26830c39952SRodrigo Vivi * xe_pm_init - Initialize Xe Power Management 26930c39952SRodrigo Vivi * @xe: xe device instance 27030c39952SRodrigo Vivi * 27130c39952SRodrigo Vivi * This component is responsible for System and Device sleep states. 272c086bfc6SHimal Prasad Ghimiray * 273c086bfc6SHimal Prasad Ghimiray * Returns 0 for success, negative error code otherwise. 27430c39952SRodrigo Vivi */ 275c086bfc6SHimal Prasad Ghimiray int xe_pm_init(struct xe_device *xe) 276ac0be3b5SAnshuman Gupta { 277c086bfc6SHimal Prasad Ghimiray int err; 278c086bfc6SHimal Prasad Ghimiray 2795349bb76SOhad Sharabi /* For now suspend/resume is only allowed with GuC */ 2805349bb76SOhad Sharabi if (!xe_device_uc_enabled(xe)) 281c086bfc6SHimal Prasad Ghimiray return 0; 282a32d82b4SRodrigo Vivi 28395ec8c1dSRiana Tauro xe->d3cold.capable = xe_pm_pci_d3cold_capable(xe); 2843d4b0bfcSAnshuman Gupta 2853d4b0bfcSAnshuman Gupta if (xe->d3cold.capable) { 286c086bfc6SHimal Prasad Ghimiray err = xe_device_sysfs_init(xe); 287c086bfc6SHimal Prasad Ghimiray if (err) 288c086bfc6SHimal Prasad Ghimiray return err; 289c086bfc6SHimal Prasad Ghimiray 290c086bfc6SHimal Prasad Ghimiray err = xe_pm_set_vram_threshold(xe, DEFAULT_VRAM_THRESHOLD); 291c086bfc6SHimal Prasad Ghimiray if (err) 292c086bfc6SHimal Prasad Ghimiray return err; 2933d4b0bfcSAnshuman Gupta } 294a32d82b4SRodrigo Vivi 295a32d82b4SRodrigo Vivi xe_pm_runtime_init(xe); 296c086bfc6SHimal Prasad Ghimiray 297c086bfc6SHimal Prasad Ghimiray return 0; 298ac0be3b5SAnshuman Gupta } 299ac0be3b5SAnshuman Gupta 30030c39952SRodrigo Vivi /** 30130c39952SRodrigo Vivi * xe_pm_runtime_fini - Finalize Runtime PM 30230c39952SRodrigo Vivi * @xe: xe device instance 30330c39952SRodrigo Vivi */ 3045b7e50e2SMatthew Auld void xe_pm_runtime_fini(struct xe_device *xe) 3055b7e50e2SMatthew Auld { 3065b7e50e2SMatthew Auld struct device *dev = xe->drm.dev; 3075b7e50e2SMatthew Auld 3085b7e50e2SMatthew Auld pm_runtime_get_sync(dev); 3095b7e50e2SMatthew Auld pm_runtime_forbid(dev); 3105b7e50e2SMatthew Auld } 3115b7e50e2SMatthew Auld 312a00b8f1aSMatthew Auld static void xe_pm_write_callback_task(struct xe_device *xe, 313a00b8f1aSMatthew Auld struct task_struct *task) 314a00b8f1aSMatthew Auld { 315a00b8f1aSMatthew Auld WRITE_ONCE(xe->pm_callback_task, task); 316a00b8f1aSMatthew Auld 317a00b8f1aSMatthew Auld /* 318a00b8f1aSMatthew Auld * Just in case it's somehow possible for our writes to be reordered to 319a00b8f1aSMatthew Auld * the extent that something else re-uses the task written in 320a00b8f1aSMatthew Auld * pm_callback_task. For example after returning from the callback, but 321a00b8f1aSMatthew Auld * before the reordered write that resets pm_callback_task back to NULL. 322a00b8f1aSMatthew Auld */ 323a00b8f1aSMatthew Auld smp_mb(); /* pairs with xe_pm_read_callback_task */ 324a00b8f1aSMatthew Auld } 325a00b8f1aSMatthew Auld 326a00b8f1aSMatthew Auld struct task_struct *xe_pm_read_callback_task(struct xe_device *xe) 327a00b8f1aSMatthew Auld { 328a00b8f1aSMatthew Auld smp_mb(); /* pairs with xe_pm_write_callback_task */ 329a00b8f1aSMatthew Auld 330a00b8f1aSMatthew Auld return READ_ONCE(xe->pm_callback_task); 331a00b8f1aSMatthew Auld } 332a00b8f1aSMatthew Auld 33330c39952SRodrigo Vivi /** 3340f9d886fSRodrigo Vivi * xe_pm_runtime_suspended - Check if runtime_pm state is suspended 3350f9d886fSRodrigo Vivi * @xe: xe device instance 3360f9d886fSRodrigo Vivi * 3370f9d886fSRodrigo Vivi * This does not provide any guarantee that the device is going to remain 3380f9d886fSRodrigo Vivi * suspended as it might be racing with the runtime state transitions. 3390f9d886fSRodrigo Vivi * It can be used only as a non-reliable assertion, to ensure that we are not in 3400f9d886fSRodrigo Vivi * the sleep state while trying to access some memory for instance. 3410f9d886fSRodrigo Vivi * 3420f9d886fSRodrigo Vivi * Returns true if PCI device is suspended, false otherwise. 3430f9d886fSRodrigo Vivi */ 3440f9d886fSRodrigo Vivi bool xe_pm_runtime_suspended(struct xe_device *xe) 3450f9d886fSRodrigo Vivi { 3460f9d886fSRodrigo Vivi return pm_runtime_suspended(xe->drm.dev); 3470f9d886fSRodrigo Vivi } 3480f9d886fSRodrigo Vivi 3490f9d886fSRodrigo Vivi /** 35030c39952SRodrigo Vivi * xe_pm_runtime_suspend - Prepare our device for D3hot/D3Cold 35130c39952SRodrigo Vivi * @xe: xe device instance 35230c39952SRodrigo Vivi * 35330c39952SRodrigo Vivi * Returns 0 for success, negative error code otherwise. 35430c39952SRodrigo Vivi */ 355dd08ebf6SMatthew Brost int xe_pm_runtime_suspend(struct xe_device *xe) 356dd08ebf6SMatthew Brost { 357fa78e188SBadal Nilawar struct xe_bo *bo, *on; 358dd08ebf6SMatthew Brost struct xe_gt *gt; 359dd08ebf6SMatthew Brost u8 id; 360a00b8f1aSMatthew Auld int err = 0; 361dd08ebf6SMatthew Brost 362275aa53fSNirmoy Das trace_xe_pm_runtime_suspend(xe, __builtin_return_address(0)); 363a00b8f1aSMatthew Auld /* Disable access_ongoing asserts and prevent recursive pm calls */ 364a00b8f1aSMatthew Auld xe_pm_write_callback_task(xe, current); 365a00b8f1aSMatthew Auld 3669700a1dfSMatthew Auld /* 3678ae84a27SRodrigo Vivi * The actual xe_pm_runtime_put() is always async underneath, so 3689700a1dfSMatthew Auld * exactly where that is called should makes no difference to us. However 3699700a1dfSMatthew Auld * we still need to be very careful with the locks that this callback 3709700a1dfSMatthew Auld * acquires and the locks that are acquired and held by any callers of 3718ae84a27SRodrigo Vivi * xe_runtime_pm_get(). We already have the matching annotation 3729700a1dfSMatthew Auld * on that side, but we also need it here. For example lockdep should be 3739700a1dfSMatthew Auld * able to tell us if the following scenario is in theory possible: 3749700a1dfSMatthew Auld * 3759700a1dfSMatthew Auld * CPU0 | CPU1 (kworker) 3769700a1dfSMatthew Auld * lock(A) | 3779700a1dfSMatthew Auld * | xe_pm_runtime_suspend() 3789700a1dfSMatthew Auld * | lock(A) 3798ae84a27SRodrigo Vivi * xe_pm_runtime_get() | 3809700a1dfSMatthew Auld * 3819700a1dfSMatthew Auld * This will clearly deadlock since rpm core needs to wait for 3829700a1dfSMatthew Auld * xe_pm_runtime_suspend() to complete, but here we are holding lock(A) 3839700a1dfSMatthew Auld * on CPU0 which prevents CPU1 making forward progress. With the 3848ae84a27SRodrigo Vivi * annotation here and in xe_pm_runtime_get() lockdep will see 3859700a1dfSMatthew Auld * the potential lock inversion and give us a nice splat. 3869700a1dfSMatthew Auld */ 387379cad69SThomas Hellström xe_rpm_lockmap_acquire(xe); 3889700a1dfSMatthew Auld 389fa78e188SBadal Nilawar /* 390fa78e188SBadal Nilawar * Applying lock for entire list op as xe_ttm_bo_destroy and xe_bo_move_notify 391fa78e188SBadal Nilawar * also checks and delets bo entry from user fault list. 392fa78e188SBadal Nilawar */ 393fa78e188SBadal Nilawar mutex_lock(&xe->mem_access.vram_userfault.lock); 394fa78e188SBadal Nilawar list_for_each_entry_safe(bo, on, 395fa78e188SBadal Nilawar &xe->mem_access.vram_userfault.list, vram_userfault_link) 396fa78e188SBadal Nilawar xe_bo_runtime_pm_release_mmap_offset(bo); 397fa78e188SBadal Nilawar mutex_unlock(&xe->mem_access.vram_userfault.lock); 398fa78e188SBadal Nilawar 39966a0f6b9SVinod Govindapillai xe_display_pm_runtime_suspend(xe); 400cb8f81c1SMaarten Lankhorst 40166a0f6b9SVinod Govindapillai if (xe->d3cold.allowed) { 402dd08ebf6SMatthew Brost err = xe_bo_evict_all(xe); 403dd08ebf6SMatthew Brost if (err) 404a00b8f1aSMatthew Auld goto out; 405dd08ebf6SMatthew Brost } 406dd08ebf6SMatthew Brost 407dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 408dd08ebf6SMatthew Brost err = xe_gt_suspend(gt); 409dd08ebf6SMatthew Brost if (err) 410a00b8f1aSMatthew Auld goto out; 411dd08ebf6SMatthew Brost } 412dd08ebf6SMatthew Brost 413dd08ebf6SMatthew Brost xe_irq_suspend(xe); 414e7b180b2SRodrigo Vivi 415e7b180b2SRodrigo Vivi if (xe->d3cold.allowed) 416e7b180b2SRodrigo Vivi xe_display_pm_suspend_late(xe); 417a00b8f1aSMatthew Auld out: 418e7b180b2SRodrigo Vivi if (err) 419e7b180b2SRodrigo Vivi xe_display_pm_resume(xe, true); 420379cad69SThomas Hellström xe_rpm_lockmap_release(xe); 421a00b8f1aSMatthew Auld xe_pm_write_callback_task(xe, NULL); 422a00b8f1aSMatthew Auld return err; 423dd08ebf6SMatthew Brost } 424dd08ebf6SMatthew Brost 42530c39952SRodrigo Vivi /** 42630c39952SRodrigo Vivi * xe_pm_runtime_resume - Waking up from D3hot/D3Cold 42730c39952SRodrigo Vivi * @xe: xe device instance 42830c39952SRodrigo Vivi * 42930c39952SRodrigo Vivi * Returns 0 for success, negative error code otherwise. 43030c39952SRodrigo Vivi */ 431dd08ebf6SMatthew Brost int xe_pm_runtime_resume(struct xe_device *xe) 432dd08ebf6SMatthew Brost { 433dd08ebf6SMatthew Brost struct xe_gt *gt; 434dd08ebf6SMatthew Brost u8 id; 435a00b8f1aSMatthew Auld int err = 0; 436a00b8f1aSMatthew Auld 437275aa53fSNirmoy Das trace_xe_pm_runtime_resume(xe, __builtin_return_address(0)); 438a00b8f1aSMatthew Auld /* Disable access_ongoing asserts and prevent recursive pm calls */ 439a00b8f1aSMatthew Auld xe_pm_write_callback_task(xe, current); 440dd08ebf6SMatthew Brost 441379cad69SThomas Hellström xe_rpm_lockmap_acquire(xe); 4429700a1dfSMatthew Auld 4438d490e01SRodrigo Vivi if (xe->d3cold.allowed) { 444933fd5ffSRiana Tauro err = xe_pcode_ready(xe, true); 445dd08ebf6SMatthew Brost if (err) 446a00b8f1aSMatthew Auld goto out; 447dd08ebf6SMatthew Brost 448e7b180b2SRodrigo Vivi xe_display_pm_resume_early(xe); 449e7b180b2SRodrigo Vivi 450dd08ebf6SMatthew Brost /* 451dd08ebf6SMatthew Brost * This only restores pinned memory which is the memory 452dd08ebf6SMatthew Brost * required for the GT(s) to resume. 453dd08ebf6SMatthew Brost */ 454dd08ebf6SMatthew Brost err = xe_bo_restore_kernel(xe); 455dd08ebf6SMatthew Brost if (err) 456a00b8f1aSMatthew Auld goto out; 457dd08ebf6SMatthew Brost } 458dd08ebf6SMatthew Brost 459dd08ebf6SMatthew Brost xe_irq_resume(xe); 460dd08ebf6SMatthew Brost 461dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) 462dd08ebf6SMatthew Brost xe_gt_resume(gt); 463dd08ebf6SMatthew Brost 46466a0f6b9SVinod Govindapillai xe_display_pm_runtime_resume(xe); 46566a0f6b9SVinod Govindapillai 4668d490e01SRodrigo Vivi if (xe->d3cold.allowed) { 467dd08ebf6SMatthew Brost err = xe_bo_restore_user(xe); 468dd08ebf6SMatthew Brost if (err) 469a00b8f1aSMatthew Auld goto out; 470dd08ebf6SMatthew Brost } 47166a0f6b9SVinod Govindapillai 472a00b8f1aSMatthew Auld out: 473379cad69SThomas Hellström xe_rpm_lockmap_release(xe); 474a00b8f1aSMatthew Auld xe_pm_write_callback_task(xe, NULL); 475a00b8f1aSMatthew Auld return err; 476dd08ebf6SMatthew Brost } 477dd08ebf6SMatthew Brost 4788ae84a27SRodrigo Vivi /* 4798ae84a27SRodrigo Vivi * For places where resume is synchronous it can be quite easy to deadlock 4808ae84a27SRodrigo Vivi * if we are not careful. Also in practice it might be quite timing 4818ae84a27SRodrigo Vivi * sensitive to ever see the 0 -> 1 transition with the callers locks 4828ae84a27SRodrigo Vivi * held, so deadlocks might exist but are hard for lockdep to ever see. 4838ae84a27SRodrigo Vivi * With this in mind, help lockdep learn about the potentially scary 4848ae84a27SRodrigo Vivi * stuff that can happen inside the runtime_resume callback by acquiring 4858ae84a27SRodrigo Vivi * a dummy lock (it doesn't protect anything and gets compiled out on 4868ae84a27SRodrigo Vivi * non-debug builds). Lockdep then only needs to see the 487379cad69SThomas Hellström * xe_pm_runtime_xxx_map -> runtime_resume callback once, and then can 488379cad69SThomas Hellström * hopefully validate all the (callers_locks) -> xe_pm_runtime_xxx_map. 4898ae84a27SRodrigo Vivi * For example if the (callers_locks) are ever grabbed in the 4908ae84a27SRodrigo Vivi * runtime_resume callback, lockdep should give us a nice splat. 4918ae84a27SRodrigo Vivi */ 492379cad69SThomas Hellström static void xe_rpm_might_enter_cb(const struct xe_device *xe) 4938ae84a27SRodrigo Vivi { 494379cad69SThomas Hellström xe_rpm_lockmap_acquire(xe); 495379cad69SThomas Hellström xe_rpm_lockmap_release(xe); 496379cad69SThomas Hellström } 497379cad69SThomas Hellström 498379cad69SThomas Hellström /* 499379cad69SThomas Hellström * Prime the lockdep maps for known locking orders that need to 500379cad69SThomas Hellström * be supported but that may not always occur on all systems. 501379cad69SThomas Hellström */ 502379cad69SThomas Hellström static void xe_pm_runtime_lockdep_prime(void) 503379cad69SThomas Hellström { 504379cad69SThomas Hellström struct dma_resv lockdep_resv; 505379cad69SThomas Hellström 506379cad69SThomas Hellström dma_resv_init(&lockdep_resv); 507379cad69SThomas Hellström lock_map_acquire(&xe_pm_runtime_d3cold_map); 508379cad69SThomas Hellström /* D3Cold takes the dma_resv locks to evict bos */ 509379cad69SThomas Hellström dma_resv_lock(&lockdep_resv, NULL); 510379cad69SThomas Hellström dma_resv_unlock(&lockdep_resv); 511379cad69SThomas Hellström lock_map_release(&xe_pm_runtime_d3cold_map); 512379cad69SThomas Hellström 513379cad69SThomas Hellström /* Shrinkers might like to wake up the device under reclaim. */ 514379cad69SThomas Hellström fs_reclaim_acquire(GFP_KERNEL); 515379cad69SThomas Hellström lock_map_acquire(&xe_pm_runtime_nod3cold_map); 516379cad69SThomas Hellström lock_map_release(&xe_pm_runtime_nod3cold_map); 517379cad69SThomas Hellström fs_reclaim_release(GFP_KERNEL); 5188ae84a27SRodrigo Vivi } 5198ae84a27SRodrigo Vivi 52030c39952SRodrigo Vivi /** 52130c39952SRodrigo Vivi * xe_pm_runtime_get - Get a runtime_pm reference and resume synchronously 52230c39952SRodrigo Vivi * @xe: xe device instance 52330c39952SRodrigo Vivi */ 5245c9da9fcSRodrigo Vivi void xe_pm_runtime_get(struct xe_device *xe) 525dd08ebf6SMatthew Brost { 526275aa53fSNirmoy Das trace_xe_pm_runtime_get(xe, __builtin_return_address(0)); 5275c9da9fcSRodrigo Vivi pm_runtime_get_noresume(xe->drm.dev); 5285c9da9fcSRodrigo Vivi 5295c9da9fcSRodrigo Vivi if (xe_pm_read_callback_task(xe) == current) 5305c9da9fcSRodrigo Vivi return; 5315c9da9fcSRodrigo Vivi 532379cad69SThomas Hellström xe_rpm_might_enter_cb(xe); 5335c9da9fcSRodrigo Vivi pm_runtime_resume(xe->drm.dev); 534dd08ebf6SMatthew Brost } 535dd08ebf6SMatthew Brost 53630c39952SRodrigo Vivi /** 53730c39952SRodrigo Vivi * xe_pm_runtime_put - Put the runtime_pm reference back and mark as idle 53830c39952SRodrigo Vivi * @xe: xe device instance 53930c39952SRodrigo Vivi */ 5405c9da9fcSRodrigo Vivi void xe_pm_runtime_put(struct xe_device *xe) 541dd08ebf6SMatthew Brost { 542275aa53fSNirmoy Das trace_xe_pm_runtime_put(xe, __builtin_return_address(0)); 5435c9da9fcSRodrigo Vivi if (xe_pm_read_callback_task(xe) == current) { 5445c9da9fcSRodrigo Vivi pm_runtime_put_noidle(xe->drm.dev); 5455c9da9fcSRodrigo Vivi } else { 546dd08ebf6SMatthew Brost pm_runtime_mark_last_busy(xe->drm.dev); 5475c9da9fcSRodrigo Vivi pm_runtime_put(xe->drm.dev); 5485c9da9fcSRodrigo Vivi } 549dd08ebf6SMatthew Brost } 550dd08ebf6SMatthew Brost 55130c39952SRodrigo Vivi /** 55223cf006bSRodrigo Vivi * xe_pm_runtime_get_ioctl - Get a runtime_pm reference before ioctl 55323cf006bSRodrigo Vivi * @xe: xe device instance 55423cf006bSRodrigo Vivi * 55523cf006bSRodrigo Vivi * Returns: Any number greater than or equal to 0 for success, negative error 55623cf006bSRodrigo Vivi * code otherwise. 55723cf006bSRodrigo Vivi */ 55823cf006bSRodrigo Vivi int xe_pm_runtime_get_ioctl(struct xe_device *xe) 55923cf006bSRodrigo Vivi { 560275aa53fSNirmoy Das trace_xe_pm_runtime_get_ioctl(xe, __builtin_return_address(0)); 56123cf006bSRodrigo Vivi if (WARN_ON(xe_pm_read_callback_task(xe) == current)) 56223cf006bSRodrigo Vivi return -ELOOP; 56323cf006bSRodrigo Vivi 564379cad69SThomas Hellström xe_rpm_might_enter_cb(xe); 56523cf006bSRodrigo Vivi return pm_runtime_get_sync(xe->drm.dev); 56623cf006bSRodrigo Vivi } 56723cf006bSRodrigo Vivi 56823cf006bSRodrigo Vivi /** 56930c39952SRodrigo Vivi * xe_pm_runtime_get_if_active - Get a runtime_pm reference if device active 57030c39952SRodrigo Vivi * @xe: xe device instance 57130c39952SRodrigo Vivi * 57246edb0a3SRodrigo Vivi * Return: True if device is awake (regardless the previous number of references) 57346edb0a3SRodrigo Vivi * and a new reference was taken, false otherwise. 57430c39952SRodrigo Vivi */ 57546edb0a3SRodrigo Vivi bool xe_pm_runtime_get_if_active(struct xe_device *xe) 576dd08ebf6SMatthew Brost { 57746edb0a3SRodrigo Vivi return pm_runtime_get_if_active(xe->drm.dev) > 0; 578dd08ebf6SMatthew Brost } 579c8a74077SAnshuman Gupta 58030c39952SRodrigo Vivi /** 581967c5d7cSRodrigo Vivi * xe_pm_runtime_get_if_in_use - Get a new reference if device is active with previous ref taken 5823b85b7bcSRodrigo Vivi * @xe: xe device instance 5833b85b7bcSRodrigo Vivi * 584967c5d7cSRodrigo Vivi * Return: True if device is awake, a previous reference had been already taken, 585967c5d7cSRodrigo Vivi * and a new reference was now taken, false otherwise. 5863b85b7bcSRodrigo Vivi */ 5873b85b7bcSRodrigo Vivi bool xe_pm_runtime_get_if_in_use(struct xe_device *xe) 5883b85b7bcSRodrigo Vivi { 5893b85b7bcSRodrigo Vivi if (xe_pm_read_callback_task(xe) == current) { 5903b85b7bcSRodrigo Vivi /* The device is awake, grab the ref and move on */ 5913b85b7bcSRodrigo Vivi pm_runtime_get_noresume(xe->drm.dev); 5923b85b7bcSRodrigo Vivi return true; 5933b85b7bcSRodrigo Vivi } 5943b85b7bcSRodrigo Vivi 5953b85b7bcSRodrigo Vivi return pm_runtime_get_if_in_use(xe->drm.dev) > 0; 5963b85b7bcSRodrigo Vivi } 5973b85b7bcSRodrigo Vivi 598ad92f523SRodrigo Vivi /* 599ad92f523SRodrigo Vivi * Very unreliable! Should only be used to suppress the false positive case 600ad92f523SRodrigo Vivi * in the missing outer rpm protection warning. 601ad92f523SRodrigo Vivi */ 602ad92f523SRodrigo Vivi static bool xe_pm_suspending_or_resuming(struct xe_device *xe) 603ad92f523SRodrigo Vivi { 604*457ca96dSArnd Bergmann #ifdef CONFIG_PM 605ad92f523SRodrigo Vivi struct device *dev = xe->drm.dev; 606ad92f523SRodrigo Vivi 607ad92f523SRodrigo Vivi return dev->power.runtime_status == RPM_SUSPENDING || 608ad92f523SRodrigo Vivi dev->power.runtime_status == RPM_RESUMING; 609*457ca96dSArnd Bergmann #else 610*457ca96dSArnd Bergmann return false; 611*457ca96dSArnd Bergmann #endif 612ad92f523SRodrigo Vivi } 613ad92f523SRodrigo Vivi 6143b85b7bcSRodrigo Vivi /** 615cbb6a741SRodrigo Vivi * xe_pm_runtime_get_noresume - Bump runtime PM usage counter without resuming 616cbb6a741SRodrigo Vivi * @xe: xe device instance 617cbb6a741SRodrigo Vivi * 618cbb6a741SRodrigo Vivi * This function should be used in inner places where it is surely already 619cbb6a741SRodrigo Vivi * protected by outer-bound callers of `xe_pm_runtime_get`. 620cbb6a741SRodrigo Vivi * It will warn if not protected. 621cbb6a741SRodrigo Vivi * The reference should be put back after this function regardless, since it 622cbb6a741SRodrigo Vivi * will always bump the usage counter, regardless. 623cbb6a741SRodrigo Vivi */ 624cbb6a741SRodrigo Vivi void xe_pm_runtime_get_noresume(struct xe_device *xe) 625cbb6a741SRodrigo Vivi { 626cbb6a741SRodrigo Vivi bool ref; 627cbb6a741SRodrigo Vivi 628cbb6a741SRodrigo Vivi ref = xe_pm_runtime_get_if_in_use(xe); 629cbb6a741SRodrigo Vivi 630ad92f523SRodrigo Vivi if (!ref) { 631cbb6a741SRodrigo Vivi pm_runtime_get_noresume(xe->drm.dev); 632ad92f523SRodrigo Vivi drm_WARN(&xe->drm, !xe_pm_suspending_or_resuming(xe), 633ad92f523SRodrigo Vivi "Missing outer runtime PM protection\n"); 634ad92f523SRodrigo Vivi } 635cbb6a741SRodrigo Vivi } 636cbb6a741SRodrigo Vivi 637cbb6a741SRodrigo Vivi /** 638d6b41378SRodrigo Vivi * xe_pm_runtime_resume_and_get - Resume, then get a runtime_pm ref if awake. 639d6b41378SRodrigo Vivi * @xe: xe device instance 640d6b41378SRodrigo Vivi * 641d6b41378SRodrigo Vivi * Returns: True if device is awake and the reference was taken, false otherwise. 642d6b41378SRodrigo Vivi */ 643d6b41378SRodrigo Vivi bool xe_pm_runtime_resume_and_get(struct xe_device *xe) 644d6b41378SRodrigo Vivi { 645d6b41378SRodrigo Vivi if (xe_pm_read_callback_task(xe) == current) { 646d6b41378SRodrigo Vivi /* The device is awake, grab the ref and move on */ 647d6b41378SRodrigo Vivi pm_runtime_get_noresume(xe->drm.dev); 648d6b41378SRodrigo Vivi return true; 649d6b41378SRodrigo Vivi } 650d6b41378SRodrigo Vivi 651379cad69SThomas Hellström xe_rpm_might_enter_cb(xe); 652d6b41378SRodrigo Vivi return pm_runtime_resume_and_get(xe->drm.dev) >= 0; 653d6b41378SRodrigo Vivi } 654d6b41378SRodrigo Vivi 655d6b41378SRodrigo Vivi /** 65630c39952SRodrigo Vivi * xe_pm_assert_unbounded_bridge - Disable PM on unbounded pcie parent bridge 65730c39952SRodrigo Vivi * @xe: xe device instance 65830c39952SRodrigo Vivi */ 659c8a74077SAnshuman Gupta void xe_pm_assert_unbounded_bridge(struct xe_device *xe) 660c8a74077SAnshuman Gupta { 661c8a74077SAnshuman Gupta struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 662c8a74077SAnshuman Gupta struct pci_dev *bridge = pci_upstream_bridge(pdev); 663c8a74077SAnshuman Gupta 664c8a74077SAnshuman Gupta if (!bridge) 665c8a74077SAnshuman Gupta return; 666c8a74077SAnshuman Gupta 667c8a74077SAnshuman Gupta if (!bridge->driver) { 668c8a74077SAnshuman Gupta drm_warn(&xe->drm, "unbounded parent pci bridge, device won't support any PM support.\n"); 669c8a74077SAnshuman Gupta device_set_pm_not_required(&pdev->dev); 670c8a74077SAnshuman Gupta } 671c8a74077SAnshuman Gupta } 672b2d75619SAnshuman Gupta 67330c39952SRodrigo Vivi /** 67430c39952SRodrigo Vivi * xe_pm_set_vram_threshold - Set a vram threshold for allowing/blocking D3Cold 67530c39952SRodrigo Vivi * @xe: xe device instance 67630c39952SRodrigo Vivi * @threshold: VRAM size in bites for the D3cold threshold 67730c39952SRodrigo Vivi * 67830c39952SRodrigo Vivi * Returns 0 for success, negative error code otherwise. 67930c39952SRodrigo Vivi */ 680b2d75619SAnshuman Gupta int xe_pm_set_vram_threshold(struct xe_device *xe, u32 threshold) 681b2d75619SAnshuman Gupta { 682b2d75619SAnshuman Gupta struct ttm_resource_manager *man; 683b2d75619SAnshuman Gupta u32 vram_total_mb = 0; 684b2d75619SAnshuman Gupta int i; 685b2d75619SAnshuman Gupta 686b2d75619SAnshuman Gupta for (i = XE_PL_VRAM0; i <= XE_PL_VRAM1; ++i) { 687b2d75619SAnshuman Gupta man = ttm_manager_type(&xe->ttm, i); 688b2d75619SAnshuman Gupta if (man) 689b2d75619SAnshuman Gupta vram_total_mb += DIV_ROUND_UP_ULL(man->size, 1024 * 1024); 690b2d75619SAnshuman Gupta } 691b2d75619SAnshuman Gupta 692b2d75619SAnshuman Gupta drm_dbg(&xe->drm, "Total vram %u mb\n", vram_total_mb); 693b2d75619SAnshuman Gupta 694b2d75619SAnshuman Gupta if (threshold > vram_total_mb) 695b2d75619SAnshuman Gupta return -EINVAL; 696b2d75619SAnshuman Gupta 697b2d75619SAnshuman Gupta mutex_lock(&xe->d3cold.lock); 698b2d75619SAnshuman Gupta xe->d3cold.vram_threshold = threshold; 699b2d75619SAnshuman Gupta mutex_unlock(&xe->d3cold.lock); 700b2d75619SAnshuman Gupta 701b2d75619SAnshuman Gupta return 0; 702b2d75619SAnshuman Gupta } 7032ef08b98SAnshuman Gupta 70430c39952SRodrigo Vivi /** 70530c39952SRodrigo Vivi * xe_pm_d3cold_allowed_toggle - Check conditions to toggle d3cold.allowed 70630c39952SRodrigo Vivi * @xe: xe device instance 70730c39952SRodrigo Vivi * 70830c39952SRodrigo Vivi * To be called during runtime_pm idle callback. 70930c39952SRodrigo Vivi * Check for all the D3Cold conditions ahead of runtime suspend. 71030c39952SRodrigo Vivi */ 7112ef08b98SAnshuman Gupta void xe_pm_d3cold_allowed_toggle(struct xe_device *xe) 7122ef08b98SAnshuman Gupta { 7132ef08b98SAnshuman Gupta struct ttm_resource_manager *man; 7142ef08b98SAnshuman Gupta u32 total_vram_used_mb = 0; 7152ef08b98SAnshuman Gupta u64 vram_used; 7162ef08b98SAnshuman Gupta int i; 7172ef08b98SAnshuman Gupta 718e07aa913SRodrigo Vivi if (!xe->d3cold.capable) { 719e07aa913SRodrigo Vivi xe->d3cold.allowed = false; 720e07aa913SRodrigo Vivi return; 721e07aa913SRodrigo Vivi } 722e07aa913SRodrigo Vivi 7232ef08b98SAnshuman Gupta for (i = XE_PL_VRAM0; i <= XE_PL_VRAM1; ++i) { 7242ef08b98SAnshuman Gupta man = ttm_manager_type(&xe->ttm, i); 7252ef08b98SAnshuman Gupta if (man) { 7262ef08b98SAnshuman Gupta vram_used = ttm_resource_manager_usage(man); 7272ef08b98SAnshuman Gupta total_vram_used_mb += DIV_ROUND_UP_ULL(vram_used, 1024 * 1024); 7282ef08b98SAnshuman Gupta } 7292ef08b98SAnshuman Gupta } 7302ef08b98SAnshuman Gupta 7312ef08b98SAnshuman Gupta mutex_lock(&xe->d3cold.lock); 7322ef08b98SAnshuman Gupta 7332ef08b98SAnshuman Gupta if (total_vram_used_mb < xe->d3cold.vram_threshold) 7342ef08b98SAnshuman Gupta xe->d3cold.allowed = true; 7352ef08b98SAnshuman Gupta else 7362ef08b98SAnshuman Gupta xe->d3cold.allowed = false; 7372ef08b98SAnshuman Gupta 7382ef08b98SAnshuman Gupta mutex_unlock(&xe->d3cold.lock); 739ff765b77SMatthew Auld 740ff765b77SMatthew Auld drm_dbg(&xe->drm, 741ff765b77SMatthew Auld "d3cold: allowed=%s\n", str_yes_no(xe->d3cold.allowed)); 7422ef08b98SAnshuman Gupta } 743379cad69SThomas Hellström 744379cad69SThomas Hellström /** 745379cad69SThomas Hellström * xe_pm_module_init() - Perform xe_pm specific module initialization. 746379cad69SThomas Hellström * 747379cad69SThomas Hellström * Return: 0 on success. Currently doesn't fail. 748379cad69SThomas Hellström */ 749379cad69SThomas Hellström int __init xe_pm_module_init(void) 750379cad69SThomas Hellström { 751379cad69SThomas Hellström xe_pm_runtime_lockdep_prime(); 752379cad69SThomas Hellström return 0; 753379cad69SThomas Hellström } 754