1 /* 2 * SPDX-License-Identifier: MIT 3 * 4 * Copyright © 2019 Intel Corporation 5 */ 6 7 #include "i915_drv.h" 8 #include "i915_globals.h" 9 #include "i915_params.h" 10 #include "intel_context.h" 11 #include "intel_engine_pm.h" 12 #include "intel_gt.h" 13 #include "intel_gt_pm.h" 14 #include "intel_gt_requests.h" 15 #include "intel_llc.h" 16 #include "intel_pm.h" 17 #include "intel_rc6.h" 18 #include "intel_rps.h" 19 #include "intel_wakeref.h" 20 21 static int __gt_unpark(struct intel_wakeref *wf) 22 { 23 struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref); 24 struct drm_i915_private *i915 = gt->i915; 25 26 GEM_TRACE("\n"); 27 28 i915_globals_unpark(); 29 30 /* 31 * It seems that the DMC likes to transition between the DC states a lot 32 * when there are no connected displays (no active power domains) during 33 * command submission. 34 * 35 * This activity has negative impact on the performance of the chip with 36 * huge latencies observed in the interrupt handler and elsewhere. 37 * 38 * Work around it by grabbing a GT IRQ power domain whilst there is any 39 * GT activity, preventing any DC state transitions. 40 */ 41 gt->awake = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ); 42 GEM_BUG_ON(!gt->awake); 43 44 intel_rps_unpark(>->rps); 45 i915_pmu_gt_unparked(i915); 46 47 intel_gt_unpark_requests(gt); 48 49 return 0; 50 } 51 52 static int __gt_park(struct intel_wakeref *wf) 53 { 54 struct intel_gt *gt = container_of(wf, typeof(*gt), wakeref); 55 intel_wakeref_t wakeref = fetch_and_zero(>->awake); 56 struct drm_i915_private *i915 = gt->i915; 57 58 GEM_TRACE("\n"); 59 60 intel_gt_park_requests(gt); 61 62 i915_vma_parked(gt); 63 i915_pmu_gt_parked(i915); 64 intel_rps_park(>->rps); 65 66 /* Everything switched off, flush any residual interrupt just in case */ 67 intel_synchronize_irq(i915); 68 69 GEM_BUG_ON(!wakeref); 70 intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ, wakeref); 71 72 i915_globals_park(); 73 74 return 0; 75 } 76 77 static const struct intel_wakeref_ops wf_ops = { 78 .get = __gt_unpark, 79 .put = __gt_park, 80 .flags = INTEL_WAKEREF_PUT_ASYNC, 81 }; 82 83 void intel_gt_pm_init_early(struct intel_gt *gt) 84 { 85 intel_wakeref_init(>->wakeref, gt->uncore->rpm, &wf_ops); 86 } 87 88 void intel_gt_pm_init(struct intel_gt *gt) 89 { 90 /* 91 * Enabling power-management should be "self-healing". If we cannot 92 * enable a feature, simply leave it disabled with a notice to the 93 * user. 94 */ 95 intel_rc6_init(>->rc6); 96 intel_rps_init(>->rps); 97 } 98 99 static bool reset_engines(struct intel_gt *gt) 100 { 101 if (INTEL_INFO(gt->i915)->gpu_reset_clobbers_display) 102 return false; 103 104 return __intel_gt_reset(gt, ALL_ENGINES) == 0; 105 } 106 107 /** 108 * intel_gt_sanitize: called after the GPU has lost power 109 * @gt: the i915 GT container 110 * @force: ignore a failed reset and sanitize engine state anyway 111 * 112 * Anytime we reset the GPU, either with an explicit GPU reset or through a 113 * PCI power cycle, the GPU loses state and we must reset our state tracking 114 * to match. Note that calling intel_gt_sanitize() if the GPU has not 115 * been reset results in much confusion! 116 */ 117 void intel_gt_sanitize(struct intel_gt *gt, bool force) 118 { 119 struct intel_engine_cs *engine; 120 enum intel_engine_id id; 121 122 GEM_TRACE("\n"); 123 124 intel_uc_sanitize(>->uc); 125 126 for_each_engine(engine, gt, id) 127 if (engine->reset.prepare) 128 engine->reset.prepare(engine); 129 130 if (reset_engines(gt) || force) { 131 for_each_engine(engine, gt, id) 132 __intel_engine_reset(engine, false); 133 } 134 135 for_each_engine(engine, gt, id) 136 if (engine->reset.finish) 137 engine->reset.finish(engine); 138 } 139 140 void intel_gt_pm_fini(struct intel_gt *gt) 141 { 142 intel_rc6_fini(>->rc6); 143 } 144 145 int intel_gt_resume(struct intel_gt *gt) 146 { 147 struct intel_engine_cs *engine; 148 enum intel_engine_id id; 149 int err = 0; 150 151 /* 152 * After resume, we may need to poke into the pinned kernel 153 * contexts to paper over any damage caused by the sudden suspend. 154 * Only the kernel contexts should remain pinned over suspend, 155 * allowing us to fixup the user contexts on their first pin. 156 */ 157 intel_gt_pm_get(gt); 158 159 intel_uncore_forcewake_get(gt->uncore, FORCEWAKE_ALL); 160 intel_rc6_sanitize(>->rc6); 161 162 intel_rps_enable(>->rps); 163 intel_llc_enable(>->llc); 164 165 for_each_engine(engine, gt, id) { 166 struct intel_context *ce; 167 168 intel_engine_pm_get(engine); 169 170 ce = engine->kernel_context; 171 if (ce) { 172 GEM_BUG_ON(!intel_context_is_pinned(ce)); 173 ce->ops->reset(ce); 174 } 175 176 engine->serial++; /* kernel context lost */ 177 err = engine->resume(engine); 178 179 intel_engine_pm_put(engine); 180 if (err) { 181 dev_err(gt->i915->drm.dev, 182 "Failed to restart %s (%d)\n", 183 engine->name, err); 184 break; 185 } 186 } 187 188 intel_rc6_enable(>->rc6); 189 intel_uncore_forcewake_put(gt->uncore, FORCEWAKE_ALL); 190 intel_gt_pm_put(gt); 191 192 return err; 193 } 194 195 static void wait_for_idle(struct intel_gt *gt) 196 { 197 if (intel_gt_wait_for_idle(gt, I915_GEM_IDLE_TIMEOUT) == -ETIME) { 198 /* 199 * Forcibly cancel outstanding work and leave 200 * the gpu quiet. 201 */ 202 intel_gt_set_wedged(gt); 203 } 204 205 intel_gt_pm_wait_for_idle(gt); 206 } 207 208 void intel_gt_suspend(struct intel_gt *gt) 209 { 210 intel_wakeref_t wakeref; 211 212 /* We expect to be idle already; but also want to be independent */ 213 wait_for_idle(gt); 214 215 with_intel_runtime_pm(gt->uncore->rpm, wakeref) { 216 intel_rps_disable(>->rps); 217 intel_rc6_disable(>->rc6); 218 intel_llc_disable(>->llc); 219 } 220 } 221 222 void intel_gt_runtime_suspend(struct intel_gt *gt) 223 { 224 intel_uc_runtime_suspend(>->uc); 225 } 226 227 int intel_gt_runtime_resume(struct intel_gt *gt) 228 { 229 intel_gt_init_swizzling(gt); 230 231 return intel_uc_runtime_resume(>->uc); 232 } 233 234 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST) 235 #include "selftest_gt_pm.c" 236 #endif 237