1 /* 2 * SPDX-License-Identifier: MIT 3 * 4 * Copyright © 2019 Intel Corporation 5 */ 6 7 #include "i915_drv.h" 8 #include "intel_engine_pm.h" 9 #include "intel_gt_pm.h" 10 #include "intel_pm.h" 11 #include "intel_wakeref.h" 12 13 static void pm_notify(struct drm_i915_private *i915, int state) 14 { 15 blocking_notifier_call_chain(&i915->gt.pm_notifications, state, i915); 16 } 17 18 static int intel_gt_unpark(struct intel_wakeref *wf) 19 { 20 struct drm_i915_private *i915 = 21 container_of(wf, typeof(*i915), gt.wakeref); 22 23 GEM_TRACE("\n"); 24 25 /* 26 * It seems that the DMC likes to transition between the DC states a lot 27 * when there are no connected displays (no active power domains) during 28 * command submission. 29 * 30 * This activity has negative impact on the performance of the chip with 31 * huge latencies observed in the interrupt handler and elsewhere. 32 * 33 * Work around it by grabbing a GT IRQ power domain whilst there is any 34 * GT activity, preventing any DC state transitions. 35 */ 36 i915->gt.awake = intel_display_power_get(i915, POWER_DOMAIN_GT_IRQ); 37 GEM_BUG_ON(!i915->gt.awake); 38 39 intel_enable_gt_powersave(i915); 40 41 i915_update_gfx_val(i915); 42 if (INTEL_GEN(i915) >= 6) 43 gen6_rps_busy(i915); 44 45 i915_pmu_gt_unparked(i915); 46 47 i915_queue_hangcheck(i915); 48 49 pm_notify(i915, INTEL_GT_UNPARK); 50 51 return 0; 52 } 53 54 void intel_gt_pm_get(struct drm_i915_private *i915) 55 { 56 intel_wakeref_get(&i915->runtime_pm, &i915->gt.wakeref, intel_gt_unpark); 57 } 58 59 static int intel_gt_park(struct intel_wakeref *wf) 60 { 61 struct drm_i915_private *i915 = 62 container_of(wf, typeof(*i915), gt.wakeref); 63 intel_wakeref_t wakeref = fetch_and_zero(&i915->gt.awake); 64 65 GEM_TRACE("\n"); 66 67 pm_notify(i915, INTEL_GT_PARK); 68 69 i915_pmu_gt_parked(i915); 70 if (INTEL_GEN(i915) >= 6) 71 gen6_rps_idle(i915); 72 73 GEM_BUG_ON(!wakeref); 74 intel_display_power_put(i915, POWER_DOMAIN_GT_IRQ, wakeref); 75 76 return 0; 77 } 78 79 void intel_gt_pm_put(struct drm_i915_private *i915) 80 { 81 intel_wakeref_put(&i915->runtime_pm, &i915->gt.wakeref, intel_gt_park); 82 } 83 84 void intel_gt_pm_init(struct drm_i915_private *i915) 85 { 86 intel_wakeref_init(&i915->gt.wakeref); 87 BLOCKING_INIT_NOTIFIER_HEAD(&i915->gt.pm_notifications); 88 } 89 90 static bool reset_engines(struct drm_i915_private *i915) 91 { 92 if (INTEL_INFO(i915)->gpu_reset_clobbers_display) 93 return false; 94 95 return intel_gpu_reset(i915, ALL_ENGINES) == 0; 96 } 97 98 /** 99 * intel_gt_sanitize: called after the GPU has lost power 100 * @i915: the i915 device 101 * @force: ignore a failed reset and sanitize engine state anyway 102 * 103 * Anytime we reset the GPU, either with an explicit GPU reset or through a 104 * PCI power cycle, the GPU loses state and we must reset our state tracking 105 * to match. Note that calling intel_gt_sanitize() if the GPU has not 106 * been reset results in much confusion! 107 */ 108 void intel_gt_sanitize(struct drm_i915_private *i915, bool force) 109 { 110 struct intel_engine_cs *engine; 111 enum intel_engine_id id; 112 113 GEM_TRACE("\n"); 114 115 if (!reset_engines(i915) && !force) 116 return; 117 118 for_each_engine(engine, i915, id) 119 intel_engine_reset(engine, false); 120 } 121 122 int intel_gt_resume(struct drm_i915_private *i915) 123 { 124 struct intel_engine_cs *engine; 125 enum intel_engine_id id; 126 int err = 0; 127 128 /* 129 * After resume, we may need to poke into the pinned kernel 130 * contexts to paper over any damage caused by the sudden suspend. 131 * Only the kernel contexts should remain pinned over suspend, 132 * allowing us to fixup the user contexts on their first pin. 133 */ 134 intel_gt_pm_get(i915); 135 for_each_engine(engine, i915, id) { 136 struct intel_context *ce; 137 138 intel_engine_pm_get(engine); 139 140 ce = engine->kernel_context; 141 if (ce) 142 ce->ops->reset(ce); 143 144 ce = engine->preempt_context; 145 if (ce) 146 ce->ops->reset(ce); 147 148 engine->serial++; /* kernel context lost */ 149 err = engine->resume(engine); 150 151 intel_engine_pm_put(engine); 152 if (err) { 153 dev_err(i915->drm.dev, 154 "Failed to restart %s (%d)\n", 155 engine->name, err); 156 break; 157 } 158 } 159 intel_gt_pm_put(i915); 160 161 return err; 162 } 163