2626
2727#include "i915_drv.h"
2828
29- unsigned int intel_engine_wakeup (struct intel_engine_cs * engine )
29+ static unsigned int __intel_breadcrumbs_wakeup (struct intel_breadcrumbs * b )
3030{
3131 struct intel_wait * wait ;
32- unsigned long flags ;
3332 unsigned int result = 0 ;
3433
35- spin_lock_irqsave (& engine -> breadcrumbs .lock , flags );
36- wait = engine -> breadcrumbs .first_wait ;
34+ wait = b -> first_wait ;
3735 if (wait ) {
3836 result = ENGINE_WAKEUP_WAITER ;
39- if (! wake_up_process (wait -> tsk ))
40- result |= ENGINE_WAKEUP_ACTIVE ;
37+ if (wake_up_process (wait -> tsk ))
38+ result |= ENGINE_WAKEUP_ASLEEP ;
4139 }
42- spin_unlock_irqrestore (& engine -> breadcrumbs .lock , flags );
40+
41+ return result ;
42+ }
43+
44+ unsigned int intel_engine_wakeup (struct intel_engine_cs * engine )
45+ {
46+ struct intel_breadcrumbs * b = & engine -> breadcrumbs ;
47+ unsigned long flags ;
48+ unsigned int result ;
49+
50+ spin_lock_irqsave (& b -> lock , flags );
51+ result = __intel_breadcrumbs_wakeup (b );
52+ spin_unlock_irqrestore (& b -> lock , flags );
4353
4454 return result ;
4555}
@@ -54,7 +64,7 @@ static void intel_breadcrumbs_hangcheck(unsigned long data)
5464 struct intel_engine_cs * engine = (struct intel_engine_cs * )data ;
5565 struct intel_breadcrumbs * b = & engine -> breadcrumbs ;
5666
57- if (!b -> irq_enabled )
67+ if (!b -> irq_armed )
5868 return ;
5969
6070 if (b -> hangcheck_interrupts != atomic_read (& engine -> irq_count )) {
@@ -63,23 +73,32 @@ static void intel_breadcrumbs_hangcheck(unsigned long data)
6373 return ;
6474 }
6575
66- /* If the waiter was currently running, assume it hasn't had a chance
76+ /* We keep the hangcheck time alive until we disarm the irq, even
77+ * if there are no waiters at present.
78+ *
79+ * If the waiter was currently running, assume it hasn't had a chance
6780 * to process the pending interrupt (e.g, low priority task on a loaded
6881 * system) and wait until it sleeps before declaring a missed interrupt.
82+ *
83+ * If the waiter was asleep (and not even pending a wakeup), then we
84+ * must have missed an interrupt as the GPU has stopped advancing
85+ * but we still have a waiter. Assuming all batches complete within
86+ * DRM_I915_HANGCHECK_JIFFIES [1.5s]!
6987 */
70- if (intel_engine_wakeup (engine ) & ENGINE_WAKEUP_ACTIVE ) {
88+ if (intel_engine_wakeup (engine ) & ENGINE_WAKEUP_ASLEEP ) {
89+ DRM_DEBUG ("Hangcheck timer elapsed... %s idle\n" , engine -> name );
90+ set_bit (engine -> id , & engine -> i915 -> gpu_error .missed_irq_rings );
91+ mod_timer (& engine -> breadcrumbs .fake_irq , jiffies + 1 );
92+ } else {
7193 mod_timer (& b -> hangcheck , wait_timeout ());
72- return ;
7394 }
74-
75- DRM_DEBUG ("Hangcheck timer elapsed... %s idle\n" , engine -> name );
76- set_bit (engine -> id , & engine -> i915 -> gpu_error .missed_irq_rings );
77- mod_timer (& engine -> breadcrumbs .fake_irq , jiffies + 1 );
7895}
7996
8097static void intel_breadcrumbs_fake_irq (unsigned long data )
8198{
8299 struct intel_engine_cs * engine = (struct intel_engine_cs * )data ;
100+ struct intel_breadcrumbs * b = & engine -> breadcrumbs ;
101+ unsigned long flags ;
83102
84103 /*
85104 * The timer persists in case we cannot enable interrupts,
@@ -88,10 +107,15 @@ static void intel_breadcrumbs_fake_irq(unsigned long data)
88107 * every jiffie in order to kick the oldest waiter to do the
89108 * coherent seqno check.
90109 */
91- if (!intel_engine_wakeup (engine ))
110+
111+ spin_lock_irqsave (& b -> lock , flags );
112+ if (!__intel_breadcrumbs_wakeup (b ))
113+ __intel_engine_disarm_breadcrumbs (engine );
114+ spin_unlock_irqrestore (& b -> lock , flags );
115+ if (!b -> irq_armed )
92116 return ;
93117
94- mod_timer (& engine -> breadcrumbs . fake_irq , jiffies + 1 );
118+ mod_timer (& b -> fake_irq , jiffies + 1 );
95119
96120 /* Ensure that even if the GPU hangs, we get woken up.
97121 *
@@ -127,6 +151,42 @@ static void irq_disable(struct intel_engine_cs *engine)
127151 spin_unlock (& engine -> i915 -> irq_lock );
128152}
129153
154+ void __intel_engine_disarm_breadcrumbs (struct intel_engine_cs * engine )
155+ {
156+ struct intel_breadcrumbs * b = & engine -> breadcrumbs ;
157+
158+ assert_spin_locked (& b -> lock );
159+
160+ if (b -> irq_enabled ) {
161+ irq_disable (engine );
162+ b -> irq_enabled = false;
163+ }
164+
165+ b -> irq_armed = false;
166+ }
167+
168+ void intel_engine_disarm_breadcrumbs (struct intel_engine_cs * engine )
169+ {
170+ struct intel_breadcrumbs * b = & engine -> breadcrumbs ;
171+ unsigned long flags ;
172+
173+ if (!b -> irq_armed )
174+ return ;
175+
176+ spin_lock_irqsave (& b -> lock , flags );
177+
178+ /* We only disarm the irq when we are idle (all requests completed),
179+ * so if there remains a sleeping waiter, it missed the request
180+ * completion.
181+ */
182+ if (__intel_breadcrumbs_wakeup (b ) & ENGINE_WAKEUP_ASLEEP )
183+ set_bit (engine -> id , & engine -> i915 -> gpu_error .missed_irq_rings );
184+
185+ __intel_engine_disarm_breadcrumbs (engine );
186+
187+ spin_unlock_irqrestore (& b -> lock , flags );
188+ }
189+
130190static bool use_fake_irq (const struct intel_breadcrumbs * b )
131191{
132192 const struct intel_engine_cs * engine =
@@ -144,16 +204,33 @@ static bool use_fake_irq(const struct intel_breadcrumbs *b)
144204 return atomic_read (& engine -> irq_count ) == b -> hangcheck_interrupts ;
145205}
146206
207+ static void enable_fake_irq (struct intel_breadcrumbs * b )
208+ {
209+ /* Ensure we never sleep indefinitely */
210+ if (!b -> irq_enabled || use_fake_irq (b ))
211+ mod_timer (& b -> fake_irq , jiffies + 1 );
212+ else
213+ mod_timer (& b -> hangcheck , wait_timeout ());
214+ }
215+
147216static void __intel_breadcrumbs_enable_irq (struct intel_breadcrumbs * b )
148217{
149218 struct intel_engine_cs * engine =
150219 container_of (b , struct intel_engine_cs , breadcrumbs );
151220 struct drm_i915_private * i915 = engine -> i915 ;
152221
153222 assert_spin_locked (& b -> lock );
154- if (b -> rpm_wakelock )
223+ if (b -> irq_armed )
155224 return ;
156225
226+ /* The breadcrumb irq will be disarmed on the interrupt after the
227+ * waiters are signaled. This gives us a single interrupt window in
228+ * which we can add a new waiter and avoid the cost of re-enabling
229+ * the irq.
230+ */
231+ b -> irq_armed = true;
232+ GEM_BUG_ON (b -> irq_enabled );
233+
157234 if (I915_SELFTEST_ONLY (b -> mock )) {
158235 /* For our mock objects we want to avoid interaction
159236 * with the real hardware (which is not set up). So
@@ -162,17 +239,15 @@ static void __intel_breadcrumbs_enable_irq(struct intel_breadcrumbs *b)
162239 * implementation to call intel_engine_wakeup()
163240 * itself when it wants to simulate a user interrupt,
164241 */
165- b -> rpm_wakelock = true;
166242 return ;
167243 }
168244
169245 /* Since we are waiting on a request, the GPU should be busy
170- * and should have its own rpm reference. For completeness,
171- * record an rpm reference for ourselves to cover the
172- * interrupt we unmask.
246+ * and should have its own rpm reference. This is tracked
247+ * by i915->gt.awake, we can forgo holding our own wakref
248+ * for the interrupt as before i915->gt.awake is released (when
249+ * the driver is idle) we disarm the breadcrumbs.
173250 */
174- intel_runtime_pm_get_noresume (i915 );
175- b -> rpm_wakelock = true;
176251
177252 /* No interrupts? Kick the waiter every jiffie! */
178253 if (intel_irqs_enabled (i915 )) {
@@ -181,34 +256,7 @@ static void __intel_breadcrumbs_enable_irq(struct intel_breadcrumbs *b)
181256 b -> irq_enabled = true;
182257 }
183258
184- /* Ensure we never sleep indefinitely */
185- if (!b -> irq_enabled || use_fake_irq (b ))
186- mod_timer (& b -> fake_irq , jiffies + 1 );
187- else
188- mod_timer (& b -> hangcheck , wait_timeout ());
189- }
190-
191- static void __intel_breadcrumbs_disable_irq (struct intel_breadcrumbs * b )
192- {
193- struct intel_engine_cs * engine =
194- container_of (b , struct intel_engine_cs , breadcrumbs );
195-
196- assert_spin_locked (& b -> lock );
197- if (!b -> rpm_wakelock )
198- return ;
199-
200- if (I915_SELFTEST_ONLY (b -> mock )) {
201- b -> rpm_wakelock = false;
202- return ;
203- }
204-
205- if (b -> irq_enabled ) {
206- irq_disable (engine );
207- b -> irq_enabled = false;
208- }
209-
210- intel_runtime_pm_put (engine -> i915 );
211- b -> rpm_wakelock = false;
259+ enable_fake_irq (b );
212260}
213261
214262static inline struct intel_wait * to_wait (struct rb_node * node )
@@ -430,7 +478,6 @@ static void __intel_engine_remove_wait(struct intel_engine_cs *engine,
430478 wake_up_process (b -> first_wait -> tsk );
431479 } else {
432480 b -> first_wait = NULL ;
433- __intel_breadcrumbs_disable_irq (b );
434481 }
435482 } else {
436483 GEM_BUG_ON (rb_first (& b -> waiters ) == & wait -> node );
@@ -722,15 +769,22 @@ void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine)
722769 cancel_fake_irq (engine );
723770 spin_lock_irq (& b -> lock );
724771
725- __intel_breadcrumbs_disable_irq (b );
726- if (intel_engine_has_waiter (engine )) {
727- __intel_breadcrumbs_enable_irq (b );
728- if (test_bit (ENGINE_IRQ_BREADCRUMB , & engine -> irq_posted ))
729- wake_up_process (b -> first_wait -> tsk );
730- } else {
731- /* sanitize the IMR and unmask any auxiliary interrupts */
772+ if (b -> irq_enabled )
773+ irq_enable (engine );
774+ else
732775 irq_disable (engine );
733- }
776+
777+ /* We set the IRQ_BREADCRUMB bit when we enable the irq presuming the
778+ * GPU is active and may have already executed the MI_USER_INTERRUPT
779+ * before the CPU is ready to receive. However, the engine is currently
780+ * idle (we haven't started it yet), there is no possibility for a
781+ * missed interrupt as we enabled the irq and so we can clear the
782+ * immediate wakeup (until a real interrupt arrives for the waiter).
783+ */
784+ clear_bit (ENGINE_IRQ_BREADCRUMB , & engine -> irq_posted );
785+
786+ if (b -> irq_armed )
787+ enable_fake_irq (b );
734788
735789 spin_unlock_irq (& b -> lock );
736790}
0 commit comments