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 */
xe_rpm_reclaim_safe(const struct xe_device * xe)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
xe_rpm_lockmap_acquire(const struct xe_device * xe)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
xe_rpm_lockmap_release(const struct xe_device * xe)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 */
xe_pm_suspend(struct xe_device * xe)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
126*25f2ff53SMaarten Lankhorst xe_display_pm_suspend(xe);
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) {
136*25f2ff53SMaarten Lankhorst xe_display_pm_resume(xe);
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 */
xe_pm_resume(struct xe_device * xe)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
190*25f2ff53SMaarten Lankhorst xe_display_pm_resume(xe);
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
xe_pm_pci_d3cold_capable(struct xe_device * xe)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
xe_pm_runtime_init(struct xe_device * xe)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
xe_pm_init_early(struct xe_device * xe)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 */
xe_pm_init(struct xe_device * xe)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 */
xe_pm_runtime_fini(struct xe_device * xe)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
xe_pm_write_callback_task(struct xe_device * xe,struct task_struct * task)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
xe_pm_read_callback_task(struct xe_device * xe)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 */
xe_pm_runtime_suspended(struct xe_device * xe)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 */
xe_pm_runtime_suspend(struct xe_device * xe)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)
419f1a4dceeSMaarten Lankhorst xe_display_pm_runtime_resume(xe);
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 */
xe_pm_runtime_resume(struct xe_device * xe)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 */
xe_rpm_might_enter_cb(const struct xe_device * xe)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 */
xe_pm_runtime_lockdep_prime(void)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 */
xe_pm_runtime_get(struct xe_device * xe)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 */
xe_pm_runtime_put(struct xe_device * xe)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 */
xe_pm_runtime_get_ioctl(struct xe_device * xe)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 */
xe_pm_runtime_get_if_active(struct xe_device * xe)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 */
xe_pm_runtime_get_if_in_use(struct xe_device * xe)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 */
xe_pm_suspending_or_resuming(struct xe_device * xe)602ad92f523SRodrigo Vivi static bool xe_pm_suspending_or_resuming(struct xe_device *xe)
603ad92f523SRodrigo Vivi {
604457ca96dSArnd 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;
609457ca96dSArnd Bergmann #else
610457ca96dSArnd Bergmann return false;
611457ca96dSArnd 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 */
xe_pm_runtime_get_noresume(struct xe_device * xe)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 */
xe_pm_runtime_resume_and_get(struct xe_device * xe)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 */
xe_pm_assert_unbounded_bridge(struct xe_device * xe)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 */
xe_pm_set_vram_threshold(struct xe_device * xe,u32 threshold)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 */
xe_pm_d3cold_allowed_toggle(struct xe_device * xe)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 */
xe_pm_module_init(void)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