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