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 10dd08ebf6SMatthew Brost #include <drm/ttm/ttm_placement.h> 11dd08ebf6SMatthew Brost 12dd08ebf6SMatthew Brost #include "xe_bo.h" 13dd08ebf6SMatthew Brost #include "xe_bo_evict.h" 14dd08ebf6SMatthew Brost #include "xe_device.h" 15dd08ebf6SMatthew Brost #include "xe_ggtt.h" 16ea9f879dSLucas De Marchi #include "xe_gt.h" 17dd08ebf6SMatthew Brost #include "xe_irq.h" 18dd08ebf6SMatthew Brost #include "xe_pcode.h" 19dd08ebf6SMatthew Brost 20dd08ebf6SMatthew Brost /** 21dd08ebf6SMatthew Brost * DOC: Xe Power Management 22dd08ebf6SMatthew Brost * 23dd08ebf6SMatthew Brost * Xe PM shall be guided by the simplicity. 24dd08ebf6SMatthew Brost * Use the simplest hook options whenever possible. 25dd08ebf6SMatthew Brost * Let's not reinvent the runtime_pm references and hooks. 26dd08ebf6SMatthew Brost * Shall have a clear separation of display and gt underneath this component. 27dd08ebf6SMatthew Brost * 28dd08ebf6SMatthew Brost * What's next: 29dd08ebf6SMatthew Brost * 30dd08ebf6SMatthew Brost * For now s2idle and s3 are only working in integrated devices. The next step 31dd08ebf6SMatthew Brost * is to iterate through all VRAM's BO backing them up into the system memory 32dd08ebf6SMatthew Brost * before allowing the system suspend. 33dd08ebf6SMatthew Brost * 34dd08ebf6SMatthew Brost * Also runtime_pm needs to be here from the beginning. 35dd08ebf6SMatthew Brost * 36dd08ebf6SMatthew Brost * RC6/RPS are also critical PM features. Let's start with GuCRC and GuC SLPC 37dd08ebf6SMatthew Brost * and no wait boost. Frequency optimizations should come on a next stage. 38dd08ebf6SMatthew Brost */ 39dd08ebf6SMatthew Brost 40dd08ebf6SMatthew Brost /** 41dd08ebf6SMatthew Brost * xe_pm_suspend - Helper for System suspend, i.e. S0->S3 / S0->S2idle 42dd08ebf6SMatthew Brost * @xe: xe device instance 43dd08ebf6SMatthew Brost * 44dd08ebf6SMatthew Brost * Return: 0 on success 45dd08ebf6SMatthew Brost */ 46dd08ebf6SMatthew Brost int xe_pm_suspend(struct xe_device *xe) 47dd08ebf6SMatthew Brost { 48dd08ebf6SMatthew Brost struct xe_gt *gt; 49dd08ebf6SMatthew Brost u8 id; 50dd08ebf6SMatthew Brost int err; 51dd08ebf6SMatthew Brost 52dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) 53dd08ebf6SMatthew Brost xe_gt_suspend_prepare(gt); 54dd08ebf6SMatthew Brost 55dd08ebf6SMatthew Brost /* FIXME: Super racey... */ 56dd08ebf6SMatthew Brost err = xe_bo_evict_all(xe); 57dd08ebf6SMatthew Brost if (err) 58dd08ebf6SMatthew Brost return err; 59dd08ebf6SMatthew Brost 60dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 61dd08ebf6SMatthew Brost err = xe_gt_suspend(gt); 62dd08ebf6SMatthew Brost if (err) 63dd08ebf6SMatthew Brost return err; 64dd08ebf6SMatthew Brost } 65dd08ebf6SMatthew Brost 66dd08ebf6SMatthew Brost xe_irq_suspend(xe); 67dd08ebf6SMatthew Brost 68dd08ebf6SMatthew Brost return 0; 69dd08ebf6SMatthew Brost } 70dd08ebf6SMatthew Brost 71dd08ebf6SMatthew Brost /** 72dd08ebf6SMatthew Brost * xe_pm_resume - Helper for System resume S3->S0 / S2idle->S0 73dd08ebf6SMatthew Brost * @xe: xe device instance 74dd08ebf6SMatthew Brost * 75dd08ebf6SMatthew Brost * Return: 0 on success 76dd08ebf6SMatthew Brost */ 77dd08ebf6SMatthew Brost int xe_pm_resume(struct xe_device *xe) 78dd08ebf6SMatthew Brost { 79dd08ebf6SMatthew Brost struct xe_gt *gt; 80dd08ebf6SMatthew Brost u8 id; 81dd08ebf6SMatthew Brost int err; 82dd08ebf6SMatthew Brost 83dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 84dd08ebf6SMatthew Brost err = xe_pcode_init(gt); 85dd08ebf6SMatthew Brost if (err) 86dd08ebf6SMatthew Brost return err; 87dd08ebf6SMatthew Brost } 88dd08ebf6SMatthew Brost 89dd08ebf6SMatthew Brost /* 90dd08ebf6SMatthew Brost * This only restores pinned memory which is the memory required for the 91dd08ebf6SMatthew Brost * GT(s) to resume. 92dd08ebf6SMatthew Brost */ 93dd08ebf6SMatthew Brost err = xe_bo_restore_kernel(xe); 94dd08ebf6SMatthew Brost if (err) 95dd08ebf6SMatthew Brost return err; 96dd08ebf6SMatthew Brost 97dd08ebf6SMatthew Brost xe_irq_resume(xe); 98dd08ebf6SMatthew Brost 99dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) 100dd08ebf6SMatthew Brost xe_gt_resume(gt); 101dd08ebf6SMatthew Brost 102dd08ebf6SMatthew Brost err = xe_bo_restore_user(xe); 103dd08ebf6SMatthew Brost if (err) 104dd08ebf6SMatthew Brost return err; 105dd08ebf6SMatthew Brost 106dd08ebf6SMatthew Brost return 0; 107dd08ebf6SMatthew Brost } 108dd08ebf6SMatthew Brost 109dd08ebf6SMatthew Brost void xe_pm_runtime_init(struct xe_device *xe) 110dd08ebf6SMatthew Brost { 111dd08ebf6SMatthew Brost struct device *dev = xe->drm.dev; 112dd08ebf6SMatthew Brost 113dd08ebf6SMatthew Brost pm_runtime_use_autosuspend(dev); 114dd08ebf6SMatthew Brost pm_runtime_set_autosuspend_delay(dev, 1000); 115dd08ebf6SMatthew Brost pm_runtime_set_active(dev); 116dd08ebf6SMatthew Brost pm_runtime_allow(dev); 117dd08ebf6SMatthew Brost pm_runtime_mark_last_busy(dev); 118dd08ebf6SMatthew Brost pm_runtime_put_autosuspend(dev); 119dd08ebf6SMatthew Brost } 120dd08ebf6SMatthew Brost 1215b7e50e2SMatthew Auld void xe_pm_runtime_fini(struct xe_device *xe) 1225b7e50e2SMatthew Auld { 1235b7e50e2SMatthew Auld struct device *dev = xe->drm.dev; 1245b7e50e2SMatthew Auld 1255b7e50e2SMatthew Auld pm_runtime_get_sync(dev); 1265b7e50e2SMatthew Auld pm_runtime_forbid(dev); 1275b7e50e2SMatthew Auld } 1285b7e50e2SMatthew Auld 129dd08ebf6SMatthew Brost int xe_pm_runtime_suspend(struct xe_device *xe) 130dd08ebf6SMatthew Brost { 131dd08ebf6SMatthew Brost struct xe_gt *gt; 132dd08ebf6SMatthew Brost u8 id; 133dd08ebf6SMatthew Brost int err; 134dd08ebf6SMatthew Brost 135dd08ebf6SMatthew Brost if (xe->d3cold_allowed) { 136dd08ebf6SMatthew Brost if (xe_device_mem_access_ongoing(xe)) 137dd08ebf6SMatthew Brost return -EBUSY; 138dd08ebf6SMatthew Brost 139dd08ebf6SMatthew Brost err = xe_bo_evict_all(xe); 140dd08ebf6SMatthew Brost if (err) 141dd08ebf6SMatthew Brost return err; 142dd08ebf6SMatthew Brost } 143dd08ebf6SMatthew Brost 144dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 145dd08ebf6SMatthew Brost err = xe_gt_suspend(gt); 146dd08ebf6SMatthew Brost if (err) 147dd08ebf6SMatthew Brost return err; 148dd08ebf6SMatthew Brost } 149dd08ebf6SMatthew Brost 150dd08ebf6SMatthew Brost xe_irq_suspend(xe); 151dd08ebf6SMatthew Brost 152dd08ebf6SMatthew Brost return 0; 153dd08ebf6SMatthew Brost } 154dd08ebf6SMatthew Brost 155dd08ebf6SMatthew Brost int xe_pm_runtime_resume(struct xe_device *xe) 156dd08ebf6SMatthew Brost { 157dd08ebf6SMatthew Brost struct xe_gt *gt; 158dd08ebf6SMatthew Brost u8 id; 159dd08ebf6SMatthew Brost int err; 160dd08ebf6SMatthew Brost 161dd08ebf6SMatthew Brost if (xe->d3cold_allowed) { 162dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 163dd08ebf6SMatthew Brost err = xe_pcode_init(gt); 164dd08ebf6SMatthew Brost if (err) 165dd08ebf6SMatthew Brost return err; 166dd08ebf6SMatthew Brost } 167dd08ebf6SMatthew Brost 168dd08ebf6SMatthew Brost /* 169dd08ebf6SMatthew Brost * This only restores pinned memory which is the memory 170dd08ebf6SMatthew Brost * required for the GT(s) to resume. 171dd08ebf6SMatthew Brost */ 172dd08ebf6SMatthew Brost err = xe_bo_restore_kernel(xe); 173dd08ebf6SMatthew Brost if (err) 174dd08ebf6SMatthew Brost return err; 175dd08ebf6SMatthew Brost } 176dd08ebf6SMatthew Brost 177dd08ebf6SMatthew Brost xe_irq_resume(xe); 178dd08ebf6SMatthew Brost 179dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) 180dd08ebf6SMatthew Brost xe_gt_resume(gt); 181dd08ebf6SMatthew Brost 182dd08ebf6SMatthew Brost if (xe->d3cold_allowed) { 183dd08ebf6SMatthew Brost err = xe_bo_restore_user(xe); 184dd08ebf6SMatthew Brost if (err) 185dd08ebf6SMatthew Brost return err; 186dd08ebf6SMatthew Brost } 187dd08ebf6SMatthew Brost 188dd08ebf6SMatthew Brost return 0; 189dd08ebf6SMatthew Brost } 190dd08ebf6SMatthew Brost 191dd08ebf6SMatthew Brost int xe_pm_runtime_get(struct xe_device *xe) 192dd08ebf6SMatthew Brost { 193dd08ebf6SMatthew Brost return pm_runtime_get_sync(xe->drm.dev); 194dd08ebf6SMatthew Brost } 195dd08ebf6SMatthew Brost 196dd08ebf6SMatthew Brost int xe_pm_runtime_put(struct xe_device *xe) 197dd08ebf6SMatthew Brost { 198dd08ebf6SMatthew Brost pm_runtime_mark_last_busy(xe->drm.dev); 199dd08ebf6SMatthew Brost return pm_runtime_put_autosuspend(xe->drm.dev); 200dd08ebf6SMatthew Brost } 201dd08ebf6SMatthew Brost 202dd08ebf6SMatthew Brost /* Return true if resume operation happened and usage count was increased */ 203dd08ebf6SMatthew Brost bool xe_pm_runtime_resume_if_suspended(struct xe_device *xe) 204dd08ebf6SMatthew Brost { 205dd08ebf6SMatthew Brost /* In case we are suspended we need to immediately wake up */ 206dd08ebf6SMatthew Brost if (pm_runtime_suspended(xe->drm.dev)) 207dd08ebf6SMatthew Brost return !pm_runtime_resume_and_get(xe->drm.dev); 208dd08ebf6SMatthew Brost 209dd08ebf6SMatthew Brost return false; 210dd08ebf6SMatthew Brost } 211dd08ebf6SMatthew Brost 212dd08ebf6SMatthew Brost int xe_pm_runtime_get_if_active(struct xe_device *xe) 213dd08ebf6SMatthew Brost { 214dd08ebf6SMatthew Brost WARN_ON(pm_runtime_suspended(xe->drm.dev)); 215dd08ebf6SMatthew Brost return pm_runtime_get_if_active(xe->drm.dev, true); 216dd08ebf6SMatthew Brost } 217*c8a74077SAnshuman Gupta 218*c8a74077SAnshuman Gupta void xe_pm_assert_unbounded_bridge(struct xe_device *xe) 219*c8a74077SAnshuman Gupta { 220*c8a74077SAnshuman Gupta struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 221*c8a74077SAnshuman Gupta struct pci_dev *bridge = pci_upstream_bridge(pdev); 222*c8a74077SAnshuman Gupta 223*c8a74077SAnshuman Gupta if (!bridge) 224*c8a74077SAnshuman Gupta return; 225*c8a74077SAnshuman Gupta 226*c8a74077SAnshuman Gupta if (!bridge->driver) { 227*c8a74077SAnshuman Gupta drm_warn(&xe->drm, "unbounded parent pci bridge, device won't support any PM support.\n"); 228*c8a74077SAnshuman Gupta device_set_pm_not_required(&pdev->dev); 229*c8a74077SAnshuman Gupta } 230*c8a74077SAnshuman Gupta } 231