15ca02815Sjsg // SPDX-License-Identifier: MIT 2c349dbc7Sjsg /* 3c349dbc7Sjsg * Copyright © 2019 Intel Corporation 4c349dbc7Sjsg */ 5c349dbc7Sjsg 61bb76ff1Sjsg #include <linux/string_helpers.h> 7c349dbc7Sjsg #include <linux/suspend.h> 8c349dbc7Sjsg 9c349dbc7Sjsg #include "i915_drv.h" 10f005ef32Sjsg #include "i915_irq.h" 11c349dbc7Sjsg #include "i915_params.h" 12c349dbc7Sjsg #include "intel_context.h" 13c349dbc7Sjsg #include "intel_engine_pm.h" 14c349dbc7Sjsg #include "intel_gt.h" 15ad8b1aafSjsg #include "intel_gt_clock_utils.h" 16c349dbc7Sjsg #include "intel_gt_pm.h" 17f005ef32Sjsg #include "intel_gt_print.h" 18c349dbc7Sjsg #include "intel_gt_requests.h" 19c349dbc7Sjsg #include "intel_llc.h" 20c349dbc7Sjsg #include "intel_rc6.h" 21c349dbc7Sjsg #include "intel_rps.h" 22c349dbc7Sjsg #include "intel_wakeref.h" 231bb76ff1Sjsg #include "pxp/intel_pxp_pm.h" 241bb76ff1Sjsg 251bb76ff1Sjsg #define I915_GT_SUSPEND_IDLE_TIMEOUT (HZ / 2) 26c349dbc7Sjsg 27c349dbc7Sjsg static void user_forcewake(struct intel_gt *gt, bool suspend) 28c349dbc7Sjsg { 29c349dbc7Sjsg int count = atomic_read(>->user_wakeref); 30c349dbc7Sjsg 31c349dbc7Sjsg /* Inside suspend/resume so single threaded, no races to worry about. */ 32c349dbc7Sjsg if (likely(!count)) 33c349dbc7Sjsg return; 34c349dbc7Sjsg 35c349dbc7Sjsg intel_gt_pm_get(gt); 36c349dbc7Sjsg if (suspend) { 37c349dbc7Sjsg GEM_BUG_ON(count > atomic_read(>->wakeref.count)); 38c349dbc7Sjsg atomic_sub(count, >->wakeref.count); 39c349dbc7Sjsg } else { 40c349dbc7Sjsg atomic_add(count, >->wakeref.count); 41c349dbc7Sjsg } 42c349dbc7Sjsg intel_gt_pm_put(gt); 43c349dbc7Sjsg } 44c349dbc7Sjsg 455ca02815Sjsg static void runtime_begin(struct intel_gt *gt) 465ca02815Sjsg { 475ca02815Sjsg local_irq_disable(); 485ca02815Sjsg #ifdef notyet 495ca02815Sjsg write_seqcount_begin(>->stats.lock); 505ca02815Sjsg #else 515ca02815Sjsg write_seqcount_begin((seqcount_t *)>->stats.lock); 525ca02815Sjsg #endif 535ca02815Sjsg gt->stats.start = ktime_get(); 545ca02815Sjsg gt->stats.active = true; 555ca02815Sjsg #ifdef notyet 565ca02815Sjsg write_seqcount_end(>->stats.lock); 575ca02815Sjsg #else 585ca02815Sjsg write_seqcount_end((seqcount_t *)>->stats.lock); 595ca02815Sjsg #endif 605ca02815Sjsg local_irq_enable(); 615ca02815Sjsg } 625ca02815Sjsg 635ca02815Sjsg static void runtime_end(struct intel_gt *gt) 645ca02815Sjsg { 655ca02815Sjsg local_irq_disable(); 665ca02815Sjsg #ifdef notyet 675ca02815Sjsg write_seqcount_begin(>->stats.lock); 685ca02815Sjsg #else 695ca02815Sjsg write_seqcount_begin((seqcount_t *)>->stats.lock); 705ca02815Sjsg #endif 715ca02815Sjsg gt->stats.active = false; 725ca02815Sjsg gt->stats.total = 735ca02815Sjsg ktime_add(gt->stats.total, 745ca02815Sjsg ktime_sub(ktime_get(), gt->stats.start)); 755ca02815Sjsg #ifdef notyet 765ca02815Sjsg write_seqcount_end(>->stats.lock); 775ca02815Sjsg #else 785ca02815Sjsg write_seqcount_end((seqcount_t *)>->stats.lock); 795ca02815Sjsg #endif 805ca02815Sjsg local_irq_enable(); 815ca02815Sjsg } 825ca02815Sjsg 83c349dbc7Sjsg static int __gt_unpark(struct intel_wakeref *wf) 84c349dbc7Sjsg { 85c349dbc7Sjsg struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref); 86c349dbc7Sjsg struct drm_i915_private *i915 = gt->i915; 87c349dbc7Sjsg 88c349dbc7Sjsg GT_TRACE(gt, "\n"); 89c349dbc7Sjsg 90c349dbc7Sjsg /* 91c349dbc7Sjsg * It seems that the DMC likes to transition between the DC states a lot 92c349dbc7Sjsg * when there are no connected displays (no active power domains) during 93c349dbc7Sjsg * command submission. 94c349dbc7Sjsg * 95c349dbc7Sjsg * This activity has negative impact on the performance of the chip with 96c349dbc7Sjsg * huge latencies observed in the interrupt handler and elsewhere. 97c349dbc7Sjsg * 98c349dbc7Sjsg * Work around it by grabbing a GT IRQ power domain whilst there is any 99c349dbc7Sjsg * GT activity, preventing any DC state transitions. 100c349dbc7Sjsg */ 101c349dbc7Sjsg gt->awake = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ); 102c349dbc7Sjsg GEM_BUG_ON(!gt->awake); 103c349dbc7Sjsg 104c349dbc7Sjsg intel_rc6_unpark(>->rc6); 105c349dbc7Sjsg intel_rps_unpark(>->rps); 106f005ef32Sjsg i915_pmu_gt_unparked(gt); 1071bb76ff1Sjsg intel_guc_busyness_unpark(gt); 108c349dbc7Sjsg 109c349dbc7Sjsg intel_gt_unpark_requests(gt); 1105ca02815Sjsg runtime_begin(gt); 111c349dbc7Sjsg 112c349dbc7Sjsg return 0; 113c349dbc7Sjsg } 114c349dbc7Sjsg 115c349dbc7Sjsg static int __gt_park(struct intel_wakeref *wf) 116c349dbc7Sjsg { 117c349dbc7Sjsg struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref); 118c349dbc7Sjsg intel_wakeref_t wakeref = fetch_and_zero(>->awake); 119c349dbc7Sjsg struct drm_i915_private *i915 = gt->i915; 120c349dbc7Sjsg 121c349dbc7Sjsg GT_TRACE(gt, "\n"); 122c349dbc7Sjsg 1235ca02815Sjsg runtime_end(gt); 124c349dbc7Sjsg intel_gt_park_requests(gt); 125c349dbc7Sjsg 1261bb76ff1Sjsg intel_guc_busyness_park(gt); 127c349dbc7Sjsg i915_vma_parked(gt); 128f005ef32Sjsg i915_pmu_gt_parked(gt); 129c349dbc7Sjsg intel_rps_park(>->rps); 130c349dbc7Sjsg intel_rc6_park(>->rc6); 131c349dbc7Sjsg 132c349dbc7Sjsg /* Everything switched off, flush any residual interrupt just in case */ 133c349dbc7Sjsg intel_synchronize_irq(i915); 134c349dbc7Sjsg 135c349dbc7Sjsg /* Defer dropping the display power well for 100ms, it's slow! */ 136c349dbc7Sjsg GEM_BUG_ON(!wakeref); 137c349dbc7Sjsg intel_display_power_put_async(i915, POWER_DOMAIN_GT_IRQ, wakeref); 138c349dbc7Sjsg 139c349dbc7Sjsg return 0; 140c349dbc7Sjsg } 141c349dbc7Sjsg 142c349dbc7Sjsg static const struct intel_wakeref_ops wf_ops = { 143c349dbc7Sjsg .get = __gt_unpark, 144c349dbc7Sjsg .put = __gt_park, 145c349dbc7Sjsg }; 146c349dbc7Sjsg 147c349dbc7Sjsg void intel_gt_pm_init_early(struct intel_gt *gt) 148c349dbc7Sjsg { 1491bb76ff1Sjsg /* 1501bb76ff1Sjsg * We access the runtime_pm structure via gt->i915 here rather than 1511bb76ff1Sjsg * gt->uncore as we do elsewhere in the file because gt->uncore is not 1521bb76ff1Sjsg * yet initialized for all tiles at this point in the driver startup. 1531bb76ff1Sjsg * runtime_pm is per-device rather than per-tile, so this is still the 1541bb76ff1Sjsg * correct structure. 1551bb76ff1Sjsg */ 156f005ef32Sjsg intel_wakeref_init(>->wakeref, gt->i915, &wf_ops); 1575ca02815Sjsg seqcount_mutex_init(>->stats.lock, >->wakeref.mutex); 158c349dbc7Sjsg } 159c349dbc7Sjsg 160c349dbc7Sjsg void intel_gt_pm_init(struct intel_gt *gt) 161c349dbc7Sjsg { 162c349dbc7Sjsg /* 163c349dbc7Sjsg * Enabling power-management should be "self-healing". If we cannot 164c349dbc7Sjsg * enable a feature, simply leave it disabled with a notice to the 165c349dbc7Sjsg * user. 166c349dbc7Sjsg */ 167c349dbc7Sjsg intel_rc6_init(>->rc6); 168c349dbc7Sjsg intel_rps_init(>->rps); 169c349dbc7Sjsg } 170c349dbc7Sjsg 171c349dbc7Sjsg static bool reset_engines(struct intel_gt *gt) 172c349dbc7Sjsg { 173c349dbc7Sjsg if (INTEL_INFO(gt->i915)->gpu_reset_clobbers_display) 174c349dbc7Sjsg return false; 175c349dbc7Sjsg 176c349dbc7Sjsg return __intel_gt_reset(gt, ALL_ENGINES) == 0; 177c349dbc7Sjsg } 178c349dbc7Sjsg 179c349dbc7Sjsg static void gt_sanitize(struct intel_gt *gt, bool force) 180c349dbc7Sjsg { 181c349dbc7Sjsg struct intel_engine_cs *engine; 182c349dbc7Sjsg enum intel_engine_id id; 183c349dbc7Sjsg intel_wakeref_t wakeref; 184c349dbc7Sjsg 1851bb76ff1Sjsg GT_TRACE(gt, "force:%s", str_yes_no(force)); 186c349dbc7Sjsg 187c349dbc7Sjsg /* Use a raw wakeref to avoid calling intel_display_power_get early */ 188c349dbc7Sjsg wakeref = intel_runtime_pm_get(gt->uncore->rpm); 189c349dbc7Sjsg intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); 190c349dbc7Sjsg 191ad8b1aafSjsg intel_gt_check_clock_frequency(gt); 192ad8b1aafSjsg 193c349dbc7Sjsg /* 194c349dbc7Sjsg * As we have just resumed the machine and woken the device up from 195c349dbc7Sjsg * deep PCI sleep (presumably D3_cold), assume the HW has been reset 196c349dbc7Sjsg * back to defaults, recovering from whatever wedged state we left it 197c349dbc7Sjsg * in and so worth trying to use the device once more. 198c349dbc7Sjsg */ 199c349dbc7Sjsg if (intel_gt_is_wedged(gt)) 200c349dbc7Sjsg intel_gt_unset_wedged(gt); 201c349dbc7Sjsg 2021bb76ff1Sjsg /* For GuC mode, ensure submission is disabled before stopping ring */ 2031bb76ff1Sjsg intel_uc_reset_prepare(>->uc); 2041bb76ff1Sjsg 2051bb76ff1Sjsg for_each_engine(engine, gt, id) { 206c349dbc7Sjsg if (engine->reset.prepare) 207c349dbc7Sjsg engine->reset.prepare(engine); 208c349dbc7Sjsg 209ad8b1aafSjsg if (engine->sanitize) 210ad8b1aafSjsg engine->sanitize(engine); 2111bb76ff1Sjsg } 212ad8b1aafSjsg 213c349dbc7Sjsg if (reset_engines(gt) || force) { 214c349dbc7Sjsg for_each_engine(engine, gt, id) 215c349dbc7Sjsg __intel_engine_reset(engine, false); 216c349dbc7Sjsg } 217c349dbc7Sjsg 2185ca02815Sjsg intel_uc_reset(>->uc, false); 2195ca02815Sjsg 220c349dbc7Sjsg for_each_engine(engine, gt, id) 221c349dbc7Sjsg if (engine->reset.finish) 222c349dbc7Sjsg engine->reset.finish(engine); 223c349dbc7Sjsg 224ad8b1aafSjsg intel_rps_sanitize(>->rps); 225ad8b1aafSjsg 226c349dbc7Sjsg intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); 227c349dbc7Sjsg intel_runtime_pm_put(gt->uncore->rpm, wakeref); 228c349dbc7Sjsg } 229c349dbc7Sjsg 230c349dbc7Sjsg void intel_gt_pm_fini(struct intel_gt *gt) 231c349dbc7Sjsg { 232c349dbc7Sjsg intel_rc6_fini(>->rc6); 233c349dbc7Sjsg } 234c349dbc7Sjsg 235c349dbc7Sjsg int intel_gt_resume(struct intel_gt *gt) 236c349dbc7Sjsg { 237c349dbc7Sjsg struct intel_engine_cs *engine; 238c349dbc7Sjsg enum intel_engine_id id; 239c349dbc7Sjsg int err; 240c349dbc7Sjsg 241ad8b1aafSjsg err = intel_gt_has_unrecoverable_error(gt); 242c349dbc7Sjsg if (err) 243c349dbc7Sjsg return err; 244c349dbc7Sjsg 245c349dbc7Sjsg GT_TRACE(gt, "\n"); 246c349dbc7Sjsg 247c349dbc7Sjsg /* 248c349dbc7Sjsg * After resume, we may need to poke into the pinned kernel 249c349dbc7Sjsg * contexts to paper over any damage caused by the sudden suspend. 250c349dbc7Sjsg * Only the kernel contexts should remain pinned over suspend, 251c349dbc7Sjsg * allowing us to fixup the user contexts on their first pin. 252c349dbc7Sjsg */ 253ad8b1aafSjsg gt_sanitize(gt, true); 254ad8b1aafSjsg 255c349dbc7Sjsg intel_gt_pm_get(gt); 256c349dbc7Sjsg 257c349dbc7Sjsg intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); 258c349dbc7Sjsg intel_rc6_sanitize(>->rc6); 259c349dbc7Sjsg if (intel_gt_is_wedged(gt)) { 260c349dbc7Sjsg err = -EIO; 261c349dbc7Sjsg goto out_fw; 262c349dbc7Sjsg } 263c349dbc7Sjsg 264c349dbc7Sjsg /* Only when the HW is re-initialised, can we replay the requests */ 265c349dbc7Sjsg err = intel_gt_init_hw(gt); 266c349dbc7Sjsg if (err) { 267f005ef32Sjsg gt_probe_error(gt, "Failed to initialize GPU, declaring it wedged!\n"); 268c349dbc7Sjsg goto err_wedged; 269c349dbc7Sjsg } 270c349dbc7Sjsg 2715ca02815Sjsg intel_uc_reset_finish(>->uc); 2725ca02815Sjsg 273c349dbc7Sjsg intel_rps_enable(>->rps); 274c349dbc7Sjsg intel_llc_enable(>->llc); 275c349dbc7Sjsg 276c349dbc7Sjsg for_each_engine(engine, gt, id) { 277c349dbc7Sjsg intel_engine_pm_get(engine); 278c349dbc7Sjsg 279c349dbc7Sjsg engine->serial++; /* kernel context lost */ 280c349dbc7Sjsg err = intel_engine_resume(engine); 281c349dbc7Sjsg 282c349dbc7Sjsg intel_engine_pm_put(engine); 283c349dbc7Sjsg if (err) { 284f005ef32Sjsg gt_err(gt, "Failed to restart %s (%d)\n", 285c349dbc7Sjsg engine->name, err); 286c349dbc7Sjsg goto err_wedged; 287c349dbc7Sjsg } 288c349dbc7Sjsg } 289c349dbc7Sjsg 290c349dbc7Sjsg intel_rc6_enable(>->rc6); 291c349dbc7Sjsg 292c349dbc7Sjsg intel_uc_resume(>->uc); 293c349dbc7Sjsg 294c349dbc7Sjsg user_forcewake(gt, false); 295c349dbc7Sjsg 296c349dbc7Sjsg out_fw: 297c349dbc7Sjsg intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); 298c349dbc7Sjsg intel_gt_pm_put(gt); 299*770b54ddSjsg intel_gt_bind_context_set_ready(gt); 300c349dbc7Sjsg return err; 301c349dbc7Sjsg 302c349dbc7Sjsg err_wedged: 303c349dbc7Sjsg intel_gt_set_wedged(gt); 304c349dbc7Sjsg goto out_fw; 305c349dbc7Sjsg } 306c349dbc7Sjsg 307c349dbc7Sjsg static void wait_for_suspend(struct intel_gt *gt) 308c349dbc7Sjsg { 309c349dbc7Sjsg if (!intel_gt_pm_is_awake(gt)) 310c349dbc7Sjsg return; 311c349dbc7Sjsg 3121bb76ff1Sjsg if (intel_gt_wait_for_idle(gt, I915_GT_SUSPEND_IDLE_TIMEOUT) == -ETIME) { 313c349dbc7Sjsg /* 314c349dbc7Sjsg * Forcibly cancel outstanding work and leave 315c349dbc7Sjsg * the gpu quiet. 316c349dbc7Sjsg */ 317c349dbc7Sjsg intel_gt_set_wedged(gt); 318c349dbc7Sjsg intel_gt_retire_requests(gt); 319c349dbc7Sjsg } 320c349dbc7Sjsg 321c349dbc7Sjsg intel_gt_pm_wait_for_idle(gt); 322c349dbc7Sjsg } 323c349dbc7Sjsg 324c349dbc7Sjsg void intel_gt_suspend_prepare(struct intel_gt *gt) 325c349dbc7Sjsg { 326*770b54ddSjsg intel_gt_bind_context_set_unready(gt); 327c349dbc7Sjsg user_forcewake(gt, true); 328c349dbc7Sjsg wait_for_suspend(gt); 329c349dbc7Sjsg } 330c349dbc7Sjsg 331c349dbc7Sjsg static suspend_state_t pm_suspend_target(void) 332c349dbc7Sjsg { 333c349dbc7Sjsg #if IS_ENABLED(CONFIG_SUSPEND) && IS_ENABLED(CONFIG_PM_SLEEP) 334c349dbc7Sjsg return pm_suspend_target_state; 335c349dbc7Sjsg #else 336c349dbc7Sjsg return PM_SUSPEND_TO_IDLE; 337c349dbc7Sjsg #endif 338c349dbc7Sjsg } 339c349dbc7Sjsg 340c349dbc7Sjsg void intel_gt_suspend_late(struct intel_gt *gt) 341c349dbc7Sjsg { 342c349dbc7Sjsg intel_wakeref_t wakeref; 343c349dbc7Sjsg 344c349dbc7Sjsg /* We expect to be idle already; but also want to be independent */ 345c349dbc7Sjsg wait_for_suspend(gt); 346c349dbc7Sjsg 347c349dbc7Sjsg if (is_mock_gt(gt)) 348c349dbc7Sjsg return; 349c349dbc7Sjsg 350c349dbc7Sjsg GEM_BUG_ON(gt->awake); 351c349dbc7Sjsg 3521bb76ff1Sjsg intel_uc_suspend(>->uc); 3531bb76ff1Sjsg 354c349dbc7Sjsg /* 355c349dbc7Sjsg * On disabling the device, we want to turn off HW access to memory 356c349dbc7Sjsg * that we no longer own. 357c349dbc7Sjsg * 358c349dbc7Sjsg * However, not all suspend-states disable the device. S0 (s2idle) 359c349dbc7Sjsg * is effectively runtime-suspend, the device is left powered on 360c349dbc7Sjsg * but needs to be put into a low power state. We need to keep 361c349dbc7Sjsg * powermanagement enabled, but we also retain system state and so 362c349dbc7Sjsg * it remains safe to keep on using our allocated memory. 363c349dbc7Sjsg */ 364c349dbc7Sjsg if (pm_suspend_target() == PM_SUSPEND_TO_IDLE) 365c349dbc7Sjsg return; 366c349dbc7Sjsg 367c349dbc7Sjsg with_intel_runtime_pm(gt->uncore->rpm, wakeref) { 368c349dbc7Sjsg intel_rps_disable(>->rps); 369c349dbc7Sjsg intel_rc6_disable(>->rc6); 370c349dbc7Sjsg intel_llc_disable(>->llc); 371c349dbc7Sjsg } 372c349dbc7Sjsg 373c349dbc7Sjsg gt_sanitize(gt, false); 374c349dbc7Sjsg 375c349dbc7Sjsg GT_TRACE(gt, "\n"); 376c349dbc7Sjsg } 377c349dbc7Sjsg 378c349dbc7Sjsg void intel_gt_runtime_suspend(struct intel_gt *gt) 379c349dbc7Sjsg { 380*770b54ddSjsg intel_gt_bind_context_set_unready(gt); 381c349dbc7Sjsg intel_uc_runtime_suspend(>->uc); 382c349dbc7Sjsg 383c349dbc7Sjsg GT_TRACE(gt, "\n"); 384c349dbc7Sjsg } 385c349dbc7Sjsg 386c349dbc7Sjsg int intel_gt_runtime_resume(struct intel_gt *gt) 387c349dbc7Sjsg { 3881bb76ff1Sjsg int ret; 3891bb76ff1Sjsg 390c349dbc7Sjsg GT_TRACE(gt, "\n"); 391c349dbc7Sjsg intel_gt_init_swizzling(gt); 392ad8b1aafSjsg intel_ggtt_restore_fences(gt->ggtt); 393c349dbc7Sjsg 3941bb76ff1Sjsg ret = intel_uc_runtime_resume(>->uc); 3951bb76ff1Sjsg if (ret) 3961bb76ff1Sjsg return ret; 3971bb76ff1Sjsg 398*770b54ddSjsg intel_gt_bind_context_set_ready(gt); 3991bb76ff1Sjsg return 0; 400c349dbc7Sjsg } 401c349dbc7Sjsg 4025ca02815Sjsg static ktime_t __intel_gt_get_awake_time(const struct intel_gt *gt) 4035ca02815Sjsg { 4045ca02815Sjsg ktime_t total = gt->stats.total; 4055ca02815Sjsg 4065ca02815Sjsg if (gt->stats.active) 4075ca02815Sjsg total = ktime_add(total, 4085ca02815Sjsg ktime_sub(ktime_get(), gt->stats.start)); 4095ca02815Sjsg 4105ca02815Sjsg return total; 4115ca02815Sjsg } 4125ca02815Sjsg 4135ca02815Sjsg ktime_t intel_gt_get_awake_time(const struct intel_gt *gt) 4145ca02815Sjsg { 4155ca02815Sjsg unsigned int seq; 4165ca02815Sjsg ktime_t total; 4175ca02815Sjsg 4187fbee575Sjsg #ifdef notyet 4195ca02815Sjsg do { 4205ca02815Sjsg seq = read_seqcount_begin(>->stats.lock); 4215ca02815Sjsg total = __intel_gt_get_awake_time(gt); 4225ca02815Sjsg } while (read_seqcount_retry(>->stats.lock, seq)); 4237fbee575Sjsg #else 4247fbee575Sjsg do { 4257fbee575Sjsg seq = read_seqcount_begin((seqcount_t *)>->stats.lock); 4267fbee575Sjsg total = __intel_gt_get_awake_time(gt); 4277fbee575Sjsg } while (read_seqcount_retry((seqcount_t *)>->stats.lock, seq)); 4287fbee575Sjsg #endif 4295ca02815Sjsg 4305ca02815Sjsg return total; 4315ca02815Sjsg } 4325ca02815Sjsg 433c349dbc7Sjsg #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 434c349dbc7Sjsg #include "selftest_gt_pm.c" 435c349dbc7Sjsg #endif 436