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" 1909d88e3bSAnshuman Gupta #include "xe_guc.h" 20dd08ebf6SMatthew Brost #include "xe_irq.h" 21dd08ebf6SMatthew Brost #include "xe_pcode.h" 22dd08ebf6SMatthew Brost 23dd08ebf6SMatthew Brost /** 24dd08ebf6SMatthew Brost * DOC: Xe Power Management 25dd08ebf6SMatthew Brost * 26dd08ebf6SMatthew Brost * Xe PM shall be guided by the simplicity. 27dd08ebf6SMatthew Brost * Use the simplest hook options whenever possible. 28dd08ebf6SMatthew Brost * Let's not reinvent the runtime_pm references and hooks. 29dd08ebf6SMatthew Brost * Shall have a clear separation of display and gt underneath this component. 30dd08ebf6SMatthew Brost * 31dd08ebf6SMatthew Brost * What's next: 32dd08ebf6SMatthew Brost * 33dd08ebf6SMatthew Brost * For now s2idle and s3 are only working in integrated devices. The next step 34dd08ebf6SMatthew Brost * is to iterate through all VRAM's BO backing them up into the system memory 35dd08ebf6SMatthew Brost * before allowing the system suspend. 36dd08ebf6SMatthew Brost * 37dd08ebf6SMatthew Brost * Also runtime_pm needs to be here from the beginning. 38dd08ebf6SMatthew Brost * 39dd08ebf6SMatthew Brost * RC6/RPS are also critical PM features. Let's start with GuCRC and GuC SLPC 40dd08ebf6SMatthew Brost * and no wait boost. Frequency optimizations should come on a next stage. 41dd08ebf6SMatthew Brost */ 42dd08ebf6SMatthew Brost 43dd08ebf6SMatthew Brost /** 44dd08ebf6SMatthew Brost * xe_pm_suspend - Helper for System suspend, i.e. S0->S3 / S0->S2idle 45dd08ebf6SMatthew Brost * @xe: xe device instance 46dd08ebf6SMatthew Brost * 47dd08ebf6SMatthew Brost * Return: 0 on success 48dd08ebf6SMatthew Brost */ 49dd08ebf6SMatthew Brost int xe_pm_suspend(struct xe_device *xe) 50dd08ebf6SMatthew Brost { 51dd08ebf6SMatthew Brost struct xe_gt *gt; 52dd08ebf6SMatthew Brost u8 id; 53dd08ebf6SMatthew Brost int err; 54dd08ebf6SMatthew Brost 55dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) 56dd08ebf6SMatthew Brost xe_gt_suspend_prepare(gt); 57dd08ebf6SMatthew Brost 58dd08ebf6SMatthew Brost /* FIXME: Super racey... */ 59dd08ebf6SMatthew Brost err = xe_bo_evict_all(xe); 60dd08ebf6SMatthew Brost if (err) 61dd08ebf6SMatthew Brost return err; 62dd08ebf6SMatthew Brost 63dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 64dd08ebf6SMatthew Brost err = xe_gt_suspend(gt); 65dd08ebf6SMatthew Brost if (err) 66dd08ebf6SMatthew Brost return err; 67dd08ebf6SMatthew Brost } 68dd08ebf6SMatthew Brost 69dd08ebf6SMatthew Brost xe_irq_suspend(xe); 70dd08ebf6SMatthew Brost 71dd08ebf6SMatthew Brost return 0; 72dd08ebf6SMatthew Brost } 73dd08ebf6SMatthew Brost 74dd08ebf6SMatthew Brost /** 75dd08ebf6SMatthew Brost * xe_pm_resume - Helper for System resume S3->S0 / S2idle->S0 76dd08ebf6SMatthew Brost * @xe: xe device instance 77dd08ebf6SMatthew Brost * 78dd08ebf6SMatthew Brost * Return: 0 on success 79dd08ebf6SMatthew Brost */ 80dd08ebf6SMatthew Brost int xe_pm_resume(struct xe_device *xe) 81dd08ebf6SMatthew Brost { 82dd08ebf6SMatthew Brost struct xe_gt *gt; 83dd08ebf6SMatthew Brost u8 id; 84dd08ebf6SMatthew Brost int err; 85dd08ebf6SMatthew Brost 86dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 87dd08ebf6SMatthew Brost err = xe_pcode_init(gt); 88dd08ebf6SMatthew Brost if (err) 89dd08ebf6SMatthew Brost return err; 90dd08ebf6SMatthew Brost } 91dd08ebf6SMatthew Brost 92dd08ebf6SMatthew Brost /* 93dd08ebf6SMatthew Brost * This only restores pinned memory which is the memory required for the 94dd08ebf6SMatthew Brost * GT(s) to resume. 95dd08ebf6SMatthew Brost */ 96dd08ebf6SMatthew Brost err = xe_bo_restore_kernel(xe); 97dd08ebf6SMatthew Brost if (err) 98dd08ebf6SMatthew Brost return err; 99dd08ebf6SMatthew Brost 100dd08ebf6SMatthew Brost xe_irq_resume(xe); 101dd08ebf6SMatthew Brost 102dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) 103dd08ebf6SMatthew Brost xe_gt_resume(gt); 104dd08ebf6SMatthew Brost 105dd08ebf6SMatthew Brost err = xe_bo_restore_user(xe); 106dd08ebf6SMatthew Brost if (err) 107dd08ebf6SMatthew Brost return err; 108dd08ebf6SMatthew Brost 109dd08ebf6SMatthew Brost return 0; 110dd08ebf6SMatthew Brost } 111dd08ebf6SMatthew Brost 112ac0be3b5SAnshuman Gupta static bool xe_pm_pci_d3cold_capable(struct pci_dev *pdev) 113ac0be3b5SAnshuman Gupta { 114ac0be3b5SAnshuman Gupta struct pci_dev *root_pdev; 115ac0be3b5SAnshuman Gupta 116ac0be3b5SAnshuman Gupta root_pdev = pcie_find_root_port(pdev); 117ac0be3b5SAnshuman Gupta if (!root_pdev) 118ac0be3b5SAnshuman Gupta return false; 119ac0be3b5SAnshuman Gupta 120ac0be3b5SAnshuman Gupta /* D3Cold requires PME capability and _PR3 power resource */ 121ac0be3b5SAnshuman Gupta if (!pci_pme_capable(root_pdev, PCI_D3cold) || !pci_pr3_present(root_pdev)) 122ac0be3b5SAnshuman Gupta return false; 123ac0be3b5SAnshuman Gupta 124ac0be3b5SAnshuman Gupta return true; 125ac0be3b5SAnshuman Gupta } 126ac0be3b5SAnshuman Gupta 127fddebcbfSAnshuman Gupta static void xe_pm_runtime_init(struct xe_device *xe) 128dd08ebf6SMatthew Brost { 129dd08ebf6SMatthew Brost struct device *dev = xe->drm.dev; 130dd08ebf6SMatthew Brost 131dd08ebf6SMatthew Brost pm_runtime_use_autosuspend(dev); 132dd08ebf6SMatthew Brost pm_runtime_set_autosuspend_delay(dev, 1000); 133dd08ebf6SMatthew Brost pm_runtime_set_active(dev); 134dd08ebf6SMatthew Brost pm_runtime_allow(dev); 135dd08ebf6SMatthew Brost pm_runtime_mark_last_busy(dev); 136dd08ebf6SMatthew Brost pm_runtime_put_autosuspend(dev); 137dd08ebf6SMatthew Brost } 138dd08ebf6SMatthew Brost 139ac0be3b5SAnshuman Gupta void xe_pm_init(struct xe_device *xe) 140ac0be3b5SAnshuman Gupta { 141ac0be3b5SAnshuman Gupta struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 142ac0be3b5SAnshuman Gupta 143b2d75619SAnshuman Gupta drmm_mutex_init(&xe->drm, &xe->d3cold.lock); 144fddebcbfSAnshuman Gupta xe_pm_runtime_init(xe); 145b2d75619SAnshuman Gupta xe->d3cold.capable = xe_pm_pci_d3cold_capable(pdev); 146b2d75619SAnshuman Gupta xe_device_sysfs_init(xe); 147b2d75619SAnshuman Gupta xe_pm_set_vram_threshold(xe, DEFAULT_VRAM_THRESHOLD); 148ac0be3b5SAnshuman Gupta } 149ac0be3b5SAnshuman Gupta 1505b7e50e2SMatthew Auld void xe_pm_runtime_fini(struct xe_device *xe) 1515b7e50e2SMatthew Auld { 1525b7e50e2SMatthew Auld struct device *dev = xe->drm.dev; 1535b7e50e2SMatthew Auld 1545b7e50e2SMatthew Auld pm_runtime_get_sync(dev); 1555b7e50e2SMatthew Auld pm_runtime_forbid(dev); 1565b7e50e2SMatthew Auld } 1575b7e50e2SMatthew Auld 158a00b8f1aSMatthew Auld static void xe_pm_write_callback_task(struct xe_device *xe, 159a00b8f1aSMatthew Auld struct task_struct *task) 160a00b8f1aSMatthew Auld { 161a00b8f1aSMatthew Auld WRITE_ONCE(xe->pm_callback_task, task); 162a00b8f1aSMatthew Auld 163a00b8f1aSMatthew Auld /* 164a00b8f1aSMatthew Auld * Just in case it's somehow possible for our writes to be reordered to 165a00b8f1aSMatthew Auld * the extent that something else re-uses the task written in 166a00b8f1aSMatthew Auld * pm_callback_task. For example after returning from the callback, but 167a00b8f1aSMatthew Auld * before the reordered write that resets pm_callback_task back to NULL. 168a00b8f1aSMatthew Auld */ 169a00b8f1aSMatthew Auld smp_mb(); /* pairs with xe_pm_read_callback_task */ 170a00b8f1aSMatthew Auld } 171a00b8f1aSMatthew Auld 172a00b8f1aSMatthew Auld struct task_struct *xe_pm_read_callback_task(struct xe_device *xe) 173a00b8f1aSMatthew Auld { 174a00b8f1aSMatthew Auld smp_mb(); /* pairs with xe_pm_write_callback_task */ 175a00b8f1aSMatthew Auld 176a00b8f1aSMatthew Auld return READ_ONCE(xe->pm_callback_task); 177a00b8f1aSMatthew Auld } 178a00b8f1aSMatthew Auld 179dd08ebf6SMatthew Brost int xe_pm_runtime_suspend(struct xe_device *xe) 180dd08ebf6SMatthew Brost { 181dd08ebf6SMatthew Brost struct xe_gt *gt; 182dd08ebf6SMatthew Brost u8 id; 183a00b8f1aSMatthew Auld int err = 0; 184dd08ebf6SMatthew Brost 185a00b8f1aSMatthew Auld if (xe->d3cold.allowed && xe_device_mem_access_ongoing(xe)) 186dd08ebf6SMatthew Brost return -EBUSY; 187dd08ebf6SMatthew Brost 188a00b8f1aSMatthew Auld /* Disable access_ongoing asserts and prevent recursive pm calls */ 189a00b8f1aSMatthew Auld xe_pm_write_callback_task(xe, current); 190a00b8f1aSMatthew Auld 1919700a1dfSMatthew Auld /* 1929700a1dfSMatthew Auld * The actual xe_device_mem_access_put() is always async underneath, so 1939700a1dfSMatthew Auld * exactly where that is called should makes no difference to us. However 1949700a1dfSMatthew Auld * we still need to be very careful with the locks that this callback 1959700a1dfSMatthew Auld * acquires and the locks that are acquired and held by any callers of 1969700a1dfSMatthew Auld * xe_device_mem_access_get(). We already have the matching annotation 1979700a1dfSMatthew Auld * on that side, but we also need it here. For example lockdep should be 1989700a1dfSMatthew Auld * able to tell us if the following scenario is in theory possible: 1999700a1dfSMatthew Auld * 2009700a1dfSMatthew Auld * CPU0 | CPU1 (kworker) 2019700a1dfSMatthew Auld * lock(A) | 2029700a1dfSMatthew Auld * | xe_pm_runtime_suspend() 2039700a1dfSMatthew Auld * | lock(A) 2049700a1dfSMatthew Auld * xe_device_mem_access_get() | 2059700a1dfSMatthew Auld * 2069700a1dfSMatthew Auld * This will clearly deadlock since rpm core needs to wait for 2079700a1dfSMatthew Auld * xe_pm_runtime_suspend() to complete, but here we are holding lock(A) 2089700a1dfSMatthew Auld * on CPU0 which prevents CPU1 making forward progress. With the 2099700a1dfSMatthew Auld * annotation here and in xe_device_mem_access_get() lockdep will see 2109700a1dfSMatthew Auld * the potential lock inversion and give us a nice splat. 2119700a1dfSMatthew Auld */ 2129700a1dfSMatthew Auld lock_map_acquire(&xe_device_mem_access_lockdep_map); 2139700a1dfSMatthew Auld 214a00b8f1aSMatthew Auld if (xe->d3cold.allowed) { 215dd08ebf6SMatthew Brost err = xe_bo_evict_all(xe); 216dd08ebf6SMatthew Brost if (err) 217a00b8f1aSMatthew Auld goto out; 218dd08ebf6SMatthew Brost } 219dd08ebf6SMatthew Brost 220dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 221dd08ebf6SMatthew Brost err = xe_gt_suspend(gt); 222dd08ebf6SMatthew Brost if (err) 223a00b8f1aSMatthew Auld goto out; 224dd08ebf6SMatthew Brost } 225dd08ebf6SMatthew Brost 226dd08ebf6SMatthew Brost xe_irq_suspend(xe); 227a00b8f1aSMatthew Auld out: 2289700a1dfSMatthew Auld lock_map_release(&xe_device_mem_access_lockdep_map); 229a00b8f1aSMatthew Auld xe_pm_write_callback_task(xe, NULL); 230a00b8f1aSMatthew Auld return err; 231dd08ebf6SMatthew Brost } 232dd08ebf6SMatthew Brost 233dd08ebf6SMatthew Brost int xe_pm_runtime_resume(struct xe_device *xe) 234dd08ebf6SMatthew Brost { 235dd08ebf6SMatthew Brost struct xe_gt *gt; 236dd08ebf6SMatthew Brost u8 id; 237a00b8f1aSMatthew Auld int err = 0; 238a00b8f1aSMatthew Auld 239a00b8f1aSMatthew Auld /* Disable access_ongoing asserts and prevent recursive pm calls */ 240a00b8f1aSMatthew Auld xe_pm_write_callback_task(xe, current); 241dd08ebf6SMatthew Brost 2429700a1dfSMatthew Auld lock_map_acquire(&xe_device_mem_access_lockdep_map); 2439700a1dfSMatthew Auld 24409d88e3bSAnshuman Gupta /* 24509d88e3bSAnshuman Gupta * It can be possible that xe has allowed d3cold but other pcie devices 24609d88e3bSAnshuman Gupta * in gfx card soc would have blocked d3cold, therefore card has not 24709d88e3bSAnshuman Gupta * really lost power. Detecting primary Gt power is sufficient. 24809d88e3bSAnshuman Gupta */ 24909d88e3bSAnshuman Gupta gt = xe_device_get_gt(xe, 0); 25009d88e3bSAnshuman Gupta xe->d3cold.power_lost = xe_guc_in_reset(>->uc.guc); 25109d88e3bSAnshuman Gupta 25209d88e3bSAnshuman Gupta if (xe->d3cold.allowed && xe->d3cold.power_lost) { 253dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) { 254dd08ebf6SMatthew Brost err = xe_pcode_init(gt); 255dd08ebf6SMatthew Brost if (err) 256a00b8f1aSMatthew Auld goto out; 257dd08ebf6SMatthew Brost } 258dd08ebf6SMatthew Brost 259dd08ebf6SMatthew Brost /* 260dd08ebf6SMatthew Brost * This only restores pinned memory which is the memory 261dd08ebf6SMatthew Brost * required for the GT(s) to resume. 262dd08ebf6SMatthew Brost */ 263dd08ebf6SMatthew Brost err = xe_bo_restore_kernel(xe); 264dd08ebf6SMatthew Brost if (err) 265a00b8f1aSMatthew Auld goto out; 266dd08ebf6SMatthew Brost } 267dd08ebf6SMatthew Brost 268dd08ebf6SMatthew Brost xe_irq_resume(xe); 269dd08ebf6SMatthew Brost 270dd08ebf6SMatthew Brost for_each_gt(gt, xe, id) 271dd08ebf6SMatthew Brost xe_gt_resume(gt); 272dd08ebf6SMatthew Brost 27309d88e3bSAnshuman Gupta if (xe->d3cold.allowed && xe->d3cold.power_lost) { 274dd08ebf6SMatthew Brost err = xe_bo_restore_user(xe); 275dd08ebf6SMatthew Brost if (err) 276a00b8f1aSMatthew Auld goto out; 277dd08ebf6SMatthew Brost } 278a00b8f1aSMatthew Auld out: 2799700a1dfSMatthew Auld lock_map_release(&xe_device_mem_access_lockdep_map); 280a00b8f1aSMatthew Auld xe_pm_write_callback_task(xe, NULL); 281a00b8f1aSMatthew Auld return err; 282dd08ebf6SMatthew Brost } 283dd08ebf6SMatthew Brost 284dd08ebf6SMatthew Brost int xe_pm_runtime_get(struct xe_device *xe) 285dd08ebf6SMatthew Brost { 286dd08ebf6SMatthew Brost return pm_runtime_get_sync(xe->drm.dev); 287dd08ebf6SMatthew Brost } 288dd08ebf6SMatthew Brost 289dd08ebf6SMatthew Brost int xe_pm_runtime_put(struct xe_device *xe) 290dd08ebf6SMatthew Brost { 291dd08ebf6SMatthew Brost pm_runtime_mark_last_busy(xe->drm.dev); 292dd08ebf6SMatthew Brost return pm_runtime_put_autosuspend(xe->drm.dev); 293dd08ebf6SMatthew Brost } 294dd08ebf6SMatthew Brost 295dd08ebf6SMatthew Brost int xe_pm_runtime_get_if_active(struct xe_device *xe) 296dd08ebf6SMatthew Brost { 297dd08ebf6SMatthew Brost return pm_runtime_get_if_active(xe->drm.dev, true); 298dd08ebf6SMatthew Brost } 299c8a74077SAnshuman Gupta 300c8a74077SAnshuman Gupta void xe_pm_assert_unbounded_bridge(struct xe_device *xe) 301c8a74077SAnshuman Gupta { 302c8a74077SAnshuman Gupta struct pci_dev *pdev = to_pci_dev(xe->drm.dev); 303c8a74077SAnshuman Gupta struct pci_dev *bridge = pci_upstream_bridge(pdev); 304c8a74077SAnshuman Gupta 305c8a74077SAnshuman Gupta if (!bridge) 306c8a74077SAnshuman Gupta return; 307c8a74077SAnshuman Gupta 308c8a74077SAnshuman Gupta if (!bridge->driver) { 309c8a74077SAnshuman Gupta drm_warn(&xe->drm, "unbounded parent pci bridge, device won't support any PM support.\n"); 310c8a74077SAnshuman Gupta device_set_pm_not_required(&pdev->dev); 311c8a74077SAnshuman Gupta } 312c8a74077SAnshuman Gupta } 313b2d75619SAnshuman Gupta 314b2d75619SAnshuman Gupta int xe_pm_set_vram_threshold(struct xe_device *xe, u32 threshold) 315b2d75619SAnshuman Gupta { 316b2d75619SAnshuman Gupta struct ttm_resource_manager *man; 317b2d75619SAnshuman Gupta u32 vram_total_mb = 0; 318b2d75619SAnshuman Gupta int i; 319b2d75619SAnshuman Gupta 320b2d75619SAnshuman Gupta for (i = XE_PL_VRAM0; i <= XE_PL_VRAM1; ++i) { 321b2d75619SAnshuman Gupta man = ttm_manager_type(&xe->ttm, i); 322b2d75619SAnshuman Gupta if (man) 323b2d75619SAnshuman Gupta vram_total_mb += DIV_ROUND_UP_ULL(man->size, 1024 * 1024); 324b2d75619SAnshuman Gupta } 325b2d75619SAnshuman Gupta 326b2d75619SAnshuman Gupta drm_dbg(&xe->drm, "Total vram %u mb\n", vram_total_mb); 327b2d75619SAnshuman Gupta 328b2d75619SAnshuman Gupta if (threshold > vram_total_mb) 329b2d75619SAnshuman Gupta return -EINVAL; 330b2d75619SAnshuman Gupta 331b2d75619SAnshuman Gupta mutex_lock(&xe->d3cold.lock); 332b2d75619SAnshuman Gupta xe->d3cold.vram_threshold = threshold; 333b2d75619SAnshuman Gupta mutex_unlock(&xe->d3cold.lock); 334b2d75619SAnshuman Gupta 335b2d75619SAnshuman Gupta return 0; 336b2d75619SAnshuman Gupta } 3372ef08b98SAnshuman Gupta 3382ef08b98SAnshuman Gupta void xe_pm_d3cold_allowed_toggle(struct xe_device *xe) 3392ef08b98SAnshuman Gupta { 3402ef08b98SAnshuman Gupta struct ttm_resource_manager *man; 3412ef08b98SAnshuman Gupta u32 total_vram_used_mb = 0; 3422ef08b98SAnshuman Gupta u64 vram_used; 3432ef08b98SAnshuman Gupta int i; 3442ef08b98SAnshuman Gupta 345*e07aa913SRodrigo Vivi if (!xe->d3cold.capable) { 346*e07aa913SRodrigo Vivi xe->d3cold.allowed = false; 347*e07aa913SRodrigo Vivi return; 348*e07aa913SRodrigo Vivi } 349*e07aa913SRodrigo Vivi 3502ef08b98SAnshuman Gupta for (i = XE_PL_VRAM0; i <= XE_PL_VRAM1; ++i) { 3512ef08b98SAnshuman Gupta man = ttm_manager_type(&xe->ttm, i); 3522ef08b98SAnshuman Gupta if (man) { 3532ef08b98SAnshuman Gupta vram_used = ttm_resource_manager_usage(man); 3542ef08b98SAnshuman Gupta total_vram_used_mb += DIV_ROUND_UP_ULL(vram_used, 1024 * 1024); 3552ef08b98SAnshuman Gupta } 3562ef08b98SAnshuman Gupta } 3572ef08b98SAnshuman Gupta 3582ef08b98SAnshuman Gupta mutex_lock(&xe->d3cold.lock); 3592ef08b98SAnshuman Gupta 3602ef08b98SAnshuman Gupta if (total_vram_used_mb < xe->d3cold.vram_threshold) 3612ef08b98SAnshuman Gupta xe->d3cold.allowed = true; 3622ef08b98SAnshuman Gupta else 3632ef08b98SAnshuman Gupta xe->d3cold.allowed = false; 3642ef08b98SAnshuman Gupta 3652ef08b98SAnshuman Gupta mutex_unlock(&xe->d3cold.lock); 3662ef08b98SAnshuman Gupta } 367