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