xref: /linux/drivers/gpu/drm/xe/xe_pm.c (revision 2ef08b98025bd09b74f68d1801995b0b068afbe7)
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 
13dd08ebf6SMatthew Brost #include "xe_bo.h"
14dd08ebf6SMatthew Brost #include "xe_bo_evict.h"
15dd08ebf6SMatthew Brost #include "xe_device.h"
16b2d75619SAnshuman Gupta #include "xe_device_sysfs.h"
17dd08ebf6SMatthew Brost #include "xe_ggtt.h"
18ea9f879dSLucas De Marchi #include "xe_gt.h"
19dd08ebf6SMatthew Brost #include "xe_irq.h"
20dd08ebf6SMatthew Brost #include "xe_pcode.h"
21dd08ebf6SMatthew Brost 
22dd08ebf6SMatthew Brost /**
23dd08ebf6SMatthew Brost  * DOC: Xe Power Management
24dd08ebf6SMatthew Brost  *
25dd08ebf6SMatthew Brost  * Xe PM shall be guided by the simplicity.
26dd08ebf6SMatthew Brost  * Use the simplest hook options whenever possible.
27dd08ebf6SMatthew Brost  * Let's not reinvent the runtime_pm references and hooks.
28dd08ebf6SMatthew Brost  * Shall have a clear separation of display and gt underneath this component.
29dd08ebf6SMatthew Brost  *
30dd08ebf6SMatthew Brost  * What's next:
31dd08ebf6SMatthew Brost  *
32dd08ebf6SMatthew Brost  * For now s2idle and s3 are only working in integrated devices. The next step
33dd08ebf6SMatthew Brost  * is to iterate through all VRAM's BO backing them up into the system memory
34dd08ebf6SMatthew Brost  * before allowing the system suspend.
35dd08ebf6SMatthew Brost  *
36dd08ebf6SMatthew Brost  * Also runtime_pm needs to be here from the beginning.
37dd08ebf6SMatthew Brost  *
38dd08ebf6SMatthew Brost  * RC6/RPS are also critical PM features. Let's start with GuCRC and GuC SLPC
39dd08ebf6SMatthew Brost  * and no wait boost. Frequency optimizations should come on a next stage.
40dd08ebf6SMatthew Brost  */
41dd08ebf6SMatthew Brost 
42dd08ebf6SMatthew Brost /**
43dd08ebf6SMatthew Brost  * xe_pm_suspend - Helper for System suspend, i.e. S0->S3 / S0->S2idle
44dd08ebf6SMatthew Brost  * @xe: xe device instance
45dd08ebf6SMatthew Brost  *
46dd08ebf6SMatthew Brost  * Return: 0 on success
47dd08ebf6SMatthew Brost  */
48dd08ebf6SMatthew Brost int xe_pm_suspend(struct xe_device *xe)
49dd08ebf6SMatthew Brost {
50dd08ebf6SMatthew Brost 	struct xe_gt *gt;
51dd08ebf6SMatthew Brost 	u8 id;
52dd08ebf6SMatthew Brost 	int err;
53dd08ebf6SMatthew Brost 
54dd08ebf6SMatthew Brost 	for_each_gt(gt, xe, id)
55dd08ebf6SMatthew Brost 		xe_gt_suspend_prepare(gt);
56dd08ebf6SMatthew Brost 
57dd08ebf6SMatthew Brost 	/* FIXME: Super racey... */
58dd08ebf6SMatthew Brost 	err = xe_bo_evict_all(xe);
59dd08ebf6SMatthew Brost 	if (err)
60dd08ebf6SMatthew Brost 		return err;
61dd08ebf6SMatthew Brost 
62dd08ebf6SMatthew Brost 	for_each_gt(gt, xe, id) {
63dd08ebf6SMatthew Brost 		err = xe_gt_suspend(gt);
64dd08ebf6SMatthew Brost 		if (err)
65dd08ebf6SMatthew Brost 			return err;
66dd08ebf6SMatthew Brost 	}
67dd08ebf6SMatthew Brost 
68dd08ebf6SMatthew Brost 	xe_irq_suspend(xe);
69dd08ebf6SMatthew Brost 
70dd08ebf6SMatthew Brost 	return 0;
71dd08ebf6SMatthew Brost }
72dd08ebf6SMatthew Brost 
73dd08ebf6SMatthew Brost /**
74dd08ebf6SMatthew Brost  * xe_pm_resume - Helper for System resume S3->S0 / S2idle->S0
75dd08ebf6SMatthew Brost  * @xe: xe device instance
76dd08ebf6SMatthew Brost  *
77dd08ebf6SMatthew Brost  * Return: 0 on success
78dd08ebf6SMatthew Brost  */
79dd08ebf6SMatthew Brost int xe_pm_resume(struct xe_device *xe)
80dd08ebf6SMatthew Brost {
81dd08ebf6SMatthew Brost 	struct xe_gt *gt;
82dd08ebf6SMatthew Brost 	u8 id;
83dd08ebf6SMatthew Brost 	int err;
84dd08ebf6SMatthew Brost 
85dd08ebf6SMatthew Brost 	for_each_gt(gt, xe, id) {
86dd08ebf6SMatthew Brost 		err = xe_pcode_init(gt);
87dd08ebf6SMatthew Brost 		if (err)
88dd08ebf6SMatthew Brost 			return err;
89dd08ebf6SMatthew Brost 	}
90dd08ebf6SMatthew Brost 
91dd08ebf6SMatthew Brost 	/*
92dd08ebf6SMatthew Brost 	 * This only restores pinned memory which is the memory required for the
93dd08ebf6SMatthew Brost 	 * GT(s) to resume.
94dd08ebf6SMatthew Brost 	 */
95dd08ebf6SMatthew Brost 	err = xe_bo_restore_kernel(xe);
96dd08ebf6SMatthew Brost 	if (err)
97dd08ebf6SMatthew Brost 		return err;
98dd08ebf6SMatthew Brost 
99dd08ebf6SMatthew Brost 	xe_irq_resume(xe);
100dd08ebf6SMatthew Brost 
101dd08ebf6SMatthew Brost 	for_each_gt(gt, xe, id)
102dd08ebf6SMatthew Brost 		xe_gt_resume(gt);
103dd08ebf6SMatthew Brost 
104dd08ebf6SMatthew Brost 	err = xe_bo_restore_user(xe);
105dd08ebf6SMatthew Brost 	if (err)
106dd08ebf6SMatthew Brost 		return err;
107dd08ebf6SMatthew Brost 
108dd08ebf6SMatthew Brost 	return 0;
109dd08ebf6SMatthew Brost }
110dd08ebf6SMatthew Brost 
111ac0be3b5SAnshuman Gupta static bool xe_pm_pci_d3cold_capable(struct pci_dev *pdev)
112ac0be3b5SAnshuman Gupta {
113ac0be3b5SAnshuman Gupta 	struct pci_dev *root_pdev;
114ac0be3b5SAnshuman Gupta 
115ac0be3b5SAnshuman Gupta 	root_pdev = pcie_find_root_port(pdev);
116ac0be3b5SAnshuman Gupta 	if (!root_pdev)
117ac0be3b5SAnshuman Gupta 		return false;
118ac0be3b5SAnshuman Gupta 
119ac0be3b5SAnshuman Gupta 	/* D3Cold requires PME capability and _PR3 power resource */
120ac0be3b5SAnshuman Gupta 	if (!pci_pme_capable(root_pdev, PCI_D3cold) || !pci_pr3_present(root_pdev))
121ac0be3b5SAnshuman Gupta 		return false;
122ac0be3b5SAnshuman Gupta 
123ac0be3b5SAnshuman Gupta 	return true;
124ac0be3b5SAnshuman Gupta }
125ac0be3b5SAnshuman Gupta 
126fddebcbfSAnshuman Gupta static void xe_pm_runtime_init(struct xe_device *xe)
127dd08ebf6SMatthew Brost {
128dd08ebf6SMatthew Brost 	struct device *dev = xe->drm.dev;
129dd08ebf6SMatthew Brost 
130dd08ebf6SMatthew Brost 	pm_runtime_use_autosuspend(dev);
131dd08ebf6SMatthew Brost 	pm_runtime_set_autosuspend_delay(dev, 1000);
132dd08ebf6SMatthew Brost 	pm_runtime_set_active(dev);
133dd08ebf6SMatthew Brost 	pm_runtime_allow(dev);
134dd08ebf6SMatthew Brost 	pm_runtime_mark_last_busy(dev);
135dd08ebf6SMatthew Brost 	pm_runtime_put_autosuspend(dev);
136dd08ebf6SMatthew Brost }
137dd08ebf6SMatthew Brost 
138ac0be3b5SAnshuman Gupta void xe_pm_init(struct xe_device *xe)
139ac0be3b5SAnshuman Gupta {
140ac0be3b5SAnshuman Gupta 	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
141ac0be3b5SAnshuman Gupta 
142b2d75619SAnshuman Gupta 	drmm_mutex_init(&xe->drm, &xe->d3cold.lock);
143fddebcbfSAnshuman Gupta 	xe_pm_runtime_init(xe);
144b2d75619SAnshuman Gupta 	xe->d3cold.capable = xe_pm_pci_d3cold_capable(pdev);
145b2d75619SAnshuman Gupta 	xe_device_sysfs_init(xe);
146b2d75619SAnshuman Gupta 	xe_pm_set_vram_threshold(xe, DEFAULT_VRAM_THRESHOLD);
147ac0be3b5SAnshuman Gupta }
148ac0be3b5SAnshuman Gupta 
1495b7e50e2SMatthew Auld void xe_pm_runtime_fini(struct xe_device *xe)
1505b7e50e2SMatthew Auld {
1515b7e50e2SMatthew Auld 	struct device *dev = xe->drm.dev;
1525b7e50e2SMatthew Auld 
1535b7e50e2SMatthew Auld 	pm_runtime_get_sync(dev);
1545b7e50e2SMatthew Auld 	pm_runtime_forbid(dev);
1555b7e50e2SMatthew Auld }
1565b7e50e2SMatthew Auld 
157dd08ebf6SMatthew Brost int xe_pm_runtime_suspend(struct xe_device *xe)
158dd08ebf6SMatthew Brost {
159dd08ebf6SMatthew Brost 	struct xe_gt *gt;
160dd08ebf6SMatthew Brost 	u8 id;
161dd08ebf6SMatthew Brost 	int err;
162dd08ebf6SMatthew Brost 
163b2d75619SAnshuman Gupta 	if (xe->d3cold.allowed) {
164dd08ebf6SMatthew Brost 		if (xe_device_mem_access_ongoing(xe))
165dd08ebf6SMatthew Brost 			return -EBUSY;
166dd08ebf6SMatthew Brost 
167dd08ebf6SMatthew Brost 		err = xe_bo_evict_all(xe);
168dd08ebf6SMatthew Brost 		if (err)
169dd08ebf6SMatthew Brost 			return err;
170dd08ebf6SMatthew Brost 	}
171dd08ebf6SMatthew Brost 
172dd08ebf6SMatthew Brost 	for_each_gt(gt, xe, id) {
173dd08ebf6SMatthew Brost 		err = xe_gt_suspend(gt);
174dd08ebf6SMatthew Brost 		if (err)
175dd08ebf6SMatthew Brost 			return err;
176dd08ebf6SMatthew Brost 	}
177dd08ebf6SMatthew Brost 
178dd08ebf6SMatthew Brost 	xe_irq_suspend(xe);
179dd08ebf6SMatthew Brost 
180dd08ebf6SMatthew Brost 	return 0;
181dd08ebf6SMatthew Brost }
182dd08ebf6SMatthew Brost 
183dd08ebf6SMatthew Brost int xe_pm_runtime_resume(struct xe_device *xe)
184dd08ebf6SMatthew Brost {
185dd08ebf6SMatthew Brost 	struct xe_gt *gt;
186dd08ebf6SMatthew Brost 	u8 id;
187dd08ebf6SMatthew Brost 	int err;
188dd08ebf6SMatthew Brost 
189b2d75619SAnshuman Gupta 	if (xe->d3cold.allowed) {
190dd08ebf6SMatthew Brost 		for_each_gt(gt, xe, id) {
191dd08ebf6SMatthew Brost 			err = xe_pcode_init(gt);
192dd08ebf6SMatthew Brost 			if (err)
193dd08ebf6SMatthew Brost 				return err;
194dd08ebf6SMatthew Brost 		}
195dd08ebf6SMatthew Brost 
196dd08ebf6SMatthew Brost 		/*
197dd08ebf6SMatthew Brost 		 * This only restores pinned memory which is the memory
198dd08ebf6SMatthew Brost 		 * required for the GT(s) to resume.
199dd08ebf6SMatthew Brost 		 */
200dd08ebf6SMatthew Brost 		err = xe_bo_restore_kernel(xe);
201dd08ebf6SMatthew Brost 		if (err)
202dd08ebf6SMatthew Brost 			return err;
203dd08ebf6SMatthew Brost 	}
204dd08ebf6SMatthew Brost 
205dd08ebf6SMatthew Brost 	xe_irq_resume(xe);
206dd08ebf6SMatthew Brost 
207dd08ebf6SMatthew Brost 	for_each_gt(gt, xe, id)
208dd08ebf6SMatthew Brost 		xe_gt_resume(gt);
209dd08ebf6SMatthew Brost 
210b2d75619SAnshuman Gupta 	if (xe->d3cold.allowed) {
211dd08ebf6SMatthew Brost 		err = xe_bo_restore_user(xe);
212dd08ebf6SMatthew Brost 		if (err)
213dd08ebf6SMatthew Brost 			return err;
214dd08ebf6SMatthew Brost 	}
215dd08ebf6SMatthew Brost 
216dd08ebf6SMatthew Brost 	return 0;
217dd08ebf6SMatthew Brost }
218dd08ebf6SMatthew Brost 
219dd08ebf6SMatthew Brost int xe_pm_runtime_get(struct xe_device *xe)
220dd08ebf6SMatthew Brost {
221dd08ebf6SMatthew Brost 	return pm_runtime_get_sync(xe->drm.dev);
222dd08ebf6SMatthew Brost }
223dd08ebf6SMatthew Brost 
224dd08ebf6SMatthew Brost int xe_pm_runtime_put(struct xe_device *xe)
225dd08ebf6SMatthew Brost {
226dd08ebf6SMatthew Brost 	pm_runtime_mark_last_busy(xe->drm.dev);
227dd08ebf6SMatthew Brost 	return pm_runtime_put_autosuspend(xe->drm.dev);
228dd08ebf6SMatthew Brost }
229dd08ebf6SMatthew Brost 
230dd08ebf6SMatthew Brost /* Return true if resume operation happened and usage count was increased */
231dd08ebf6SMatthew Brost bool xe_pm_runtime_resume_if_suspended(struct xe_device *xe)
232dd08ebf6SMatthew Brost {
233dd08ebf6SMatthew Brost 	/* In case we are suspended we need to immediately wake up */
234dd08ebf6SMatthew Brost 	if (pm_runtime_suspended(xe->drm.dev))
235dd08ebf6SMatthew Brost 		return !pm_runtime_resume_and_get(xe->drm.dev);
236dd08ebf6SMatthew Brost 
237dd08ebf6SMatthew Brost 	return false;
238dd08ebf6SMatthew Brost }
239dd08ebf6SMatthew Brost 
240dd08ebf6SMatthew Brost int xe_pm_runtime_get_if_active(struct xe_device *xe)
241dd08ebf6SMatthew Brost {
242dd08ebf6SMatthew Brost 	WARN_ON(pm_runtime_suspended(xe->drm.dev));
243dd08ebf6SMatthew Brost 	return pm_runtime_get_if_active(xe->drm.dev, true);
244dd08ebf6SMatthew Brost }
245c8a74077SAnshuman Gupta 
246c8a74077SAnshuman Gupta void xe_pm_assert_unbounded_bridge(struct xe_device *xe)
247c8a74077SAnshuman Gupta {
248c8a74077SAnshuman Gupta 	struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
249c8a74077SAnshuman Gupta 	struct pci_dev *bridge = pci_upstream_bridge(pdev);
250c8a74077SAnshuman Gupta 
251c8a74077SAnshuman Gupta 	if (!bridge)
252c8a74077SAnshuman Gupta 		return;
253c8a74077SAnshuman Gupta 
254c8a74077SAnshuman Gupta 	if (!bridge->driver) {
255c8a74077SAnshuman Gupta 		drm_warn(&xe->drm, "unbounded parent pci bridge, device won't support any PM support.\n");
256c8a74077SAnshuman Gupta 		device_set_pm_not_required(&pdev->dev);
257c8a74077SAnshuman Gupta 	}
258c8a74077SAnshuman Gupta }
259b2d75619SAnshuman Gupta 
260b2d75619SAnshuman Gupta int xe_pm_set_vram_threshold(struct xe_device *xe, u32 threshold)
261b2d75619SAnshuman Gupta {
262b2d75619SAnshuman Gupta 	struct ttm_resource_manager *man;
263b2d75619SAnshuman Gupta 	u32 vram_total_mb = 0;
264b2d75619SAnshuman Gupta 	int i;
265b2d75619SAnshuman Gupta 
266b2d75619SAnshuman Gupta 	for (i = XE_PL_VRAM0; i <= XE_PL_VRAM1; ++i) {
267b2d75619SAnshuman Gupta 		man = ttm_manager_type(&xe->ttm, i);
268b2d75619SAnshuman Gupta 		if (man)
269b2d75619SAnshuman Gupta 			vram_total_mb += DIV_ROUND_UP_ULL(man->size, 1024 * 1024);
270b2d75619SAnshuman Gupta 	}
271b2d75619SAnshuman Gupta 
272b2d75619SAnshuman Gupta 	drm_dbg(&xe->drm, "Total vram %u mb\n", vram_total_mb);
273b2d75619SAnshuman Gupta 
274b2d75619SAnshuman Gupta 	if (threshold > vram_total_mb)
275b2d75619SAnshuman Gupta 		return -EINVAL;
276b2d75619SAnshuman Gupta 
277b2d75619SAnshuman Gupta 	mutex_lock(&xe->d3cold.lock);
278b2d75619SAnshuman Gupta 	xe->d3cold.vram_threshold = threshold;
279b2d75619SAnshuman Gupta 	mutex_unlock(&xe->d3cold.lock);
280b2d75619SAnshuman Gupta 
281b2d75619SAnshuman Gupta 	return 0;
282b2d75619SAnshuman Gupta }
283*2ef08b98SAnshuman Gupta 
284*2ef08b98SAnshuman Gupta void xe_pm_d3cold_allowed_toggle(struct xe_device *xe)
285*2ef08b98SAnshuman Gupta {
286*2ef08b98SAnshuman Gupta 	struct ttm_resource_manager *man;
287*2ef08b98SAnshuman Gupta 	u32 total_vram_used_mb = 0;
288*2ef08b98SAnshuman Gupta 	u64 vram_used;
289*2ef08b98SAnshuman Gupta 	int i;
290*2ef08b98SAnshuman Gupta 
291*2ef08b98SAnshuman Gupta 	for (i = XE_PL_VRAM0; i <= XE_PL_VRAM1; ++i) {
292*2ef08b98SAnshuman Gupta 		man = ttm_manager_type(&xe->ttm, i);
293*2ef08b98SAnshuman Gupta 		if (man) {
294*2ef08b98SAnshuman Gupta 			vram_used = ttm_resource_manager_usage(man);
295*2ef08b98SAnshuman Gupta 			total_vram_used_mb += DIV_ROUND_UP_ULL(vram_used, 1024 * 1024);
296*2ef08b98SAnshuman Gupta 		}
297*2ef08b98SAnshuman Gupta 	}
298*2ef08b98SAnshuman Gupta 
299*2ef08b98SAnshuman Gupta 	mutex_lock(&xe->d3cold.lock);
300*2ef08b98SAnshuman Gupta 
301*2ef08b98SAnshuman Gupta 	if (total_vram_used_mb < xe->d3cold.vram_threshold)
302*2ef08b98SAnshuman Gupta 		xe->d3cold.allowed = true;
303*2ef08b98SAnshuman Gupta 	else
304*2ef08b98SAnshuman Gupta 		xe->d3cold.allowed = false;
305*2ef08b98SAnshuman Gupta 
306*2ef08b98SAnshuman Gupta 	mutex_unlock(&xe->d3cold.lock);
307*2ef08b98SAnshuman Gupta }
308