diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ringbuffer.h')
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.h | 135 |
1 files changed, 105 insertions, 30 deletions
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h index b33c876fed20..12cb7ed90014 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.h +++ b/drivers/gpu/drm/i915/intel_ringbuffer.h | |||
@@ -62,18 +62,6 @@ struct intel_hw_status_page { | |||
62 | (i915_gem_obj_ggtt_offset(dev_priv->semaphore_obj) + \ | 62 | (i915_gem_obj_ggtt_offset(dev_priv->semaphore_obj) + \ |
63 | GEN8_SEMAPHORE_OFFSET(from, (__ring)->id)) | 63 | GEN8_SEMAPHORE_OFFSET(from, (__ring)->id)) |
64 | 64 | ||
65 | #define GEN8_RING_SEMAPHORE_INIT(e) do { \ | ||
66 | if (!dev_priv->semaphore_obj) { \ | ||
67 | break; \ | ||
68 | } \ | ||
69 | (e)->semaphore.signal_ggtt[RCS] = GEN8_SIGNAL_OFFSET((e), RCS); \ | ||
70 | (e)->semaphore.signal_ggtt[VCS] = GEN8_SIGNAL_OFFSET((e), VCS); \ | ||
71 | (e)->semaphore.signal_ggtt[BCS] = GEN8_SIGNAL_OFFSET((e), BCS); \ | ||
72 | (e)->semaphore.signal_ggtt[VECS] = GEN8_SIGNAL_OFFSET((e), VECS); \ | ||
73 | (e)->semaphore.signal_ggtt[VCS2] = GEN8_SIGNAL_OFFSET((e), VCS2); \ | ||
74 | (e)->semaphore.signal_ggtt[(e)->id] = MI_SEMAPHORE_SYNC_INVALID; \ | ||
75 | } while(0) | ||
76 | |||
77 | enum intel_ring_hangcheck_action { | 65 | enum intel_ring_hangcheck_action { |
78 | HANGCHECK_IDLE = 0, | 66 | HANGCHECK_IDLE = 0, |
79 | HANGCHECK_WAIT, | 67 | HANGCHECK_WAIT, |
@@ -86,8 +74,8 @@ enum intel_ring_hangcheck_action { | |||
86 | 74 | ||
87 | struct intel_ring_hangcheck { | 75 | struct intel_ring_hangcheck { |
88 | u64 acthd; | 76 | u64 acthd; |
77 | unsigned long user_interrupts; | ||
89 | u32 seqno; | 78 | u32 seqno; |
90 | unsigned user_interrupts; | ||
91 | int score; | 79 | int score; |
92 | enum intel_ring_hangcheck_action action; | 80 | enum intel_ring_hangcheck_action action; |
93 | int deadlock; | 81 | int deadlock; |
@@ -141,6 +129,8 @@ struct i915_ctx_workarounds { | |||
141 | struct drm_i915_gem_object *obj; | 129 | struct drm_i915_gem_object *obj; |
142 | }; | 130 | }; |
143 | 131 | ||
132 | struct drm_i915_gem_request; | ||
133 | |||
144 | struct intel_engine_cs { | 134 | struct intel_engine_cs { |
145 | struct drm_i915_private *i915; | 135 | struct drm_i915_private *i915; |
146 | const char *name; | 136 | const char *name; |
@@ -160,6 +150,39 @@ struct intel_engine_cs { | |||
160 | struct intel_ringbuffer *buffer; | 150 | struct intel_ringbuffer *buffer; |
161 | struct list_head buffers; | 151 | struct list_head buffers; |
162 | 152 | ||
153 | /* Rather than have every client wait upon all user interrupts, | ||
154 | * with the herd waking after every interrupt and each doing the | ||
155 | * heavyweight seqno dance, we delegate the task (of being the | ||
156 | * bottom-half of the user interrupt) to the first client. After | ||
157 | * every interrupt, we wake up one client, who does the heavyweight | ||
158 | * coherent seqno read and either goes back to sleep (if incomplete), | ||
159 | * or wakes up all the completed clients in parallel, before then | ||
160 | * transferring the bottom-half status to the next client in the queue. | ||
161 | * | ||
162 | * Compared to walking the entire list of waiters in a single dedicated | ||
163 | * bottom-half, we reduce the latency of the first waiter by avoiding | ||
164 | * a context switch, but incur additional coherent seqno reads when | ||
165 | * following the chain of request breadcrumbs. Since it is most likely | ||
166 | * that we have a single client waiting on each seqno, then reducing | ||
167 | * the overhead of waking that client is much preferred. | ||
168 | */ | ||
169 | struct intel_breadcrumbs { | ||
170 | struct task_struct *irq_seqno_bh; /* bh for user interrupts */ | ||
171 | unsigned long irq_wakeups; | ||
172 | bool irq_posted; | ||
173 | |||
174 | spinlock_t lock; /* protects the lists of requests */ | ||
175 | struct rb_root waiters; /* sorted by retirement, priority */ | ||
176 | struct rb_root signals; /* sorted by retirement */ | ||
177 | struct intel_wait *first_wait; /* oldest waiter by retirement */ | ||
178 | struct task_struct *signaler; /* used for fence signalling */ | ||
179 | struct drm_i915_gem_request *first_signal; | ||
180 | struct timer_list fake_irq; /* used after a missed interrupt */ | ||
181 | |||
182 | bool irq_enabled : 1; | ||
183 | bool rpm_wakelock : 1; | ||
184 | } breadcrumbs; | ||
185 | |||
163 | /* | 186 | /* |
164 | * A pool of objects to use as shadow copies of client batch buffers | 187 | * A pool of objects to use as shadow copies of client batch buffers |
165 | * when the command parser is enabled. Prevents the client from | 188 | * when the command parser is enabled. Prevents the client from |
@@ -170,11 +193,10 @@ struct intel_engine_cs { | |||
170 | struct intel_hw_status_page status_page; | 193 | struct intel_hw_status_page status_page; |
171 | struct i915_ctx_workarounds wa_ctx; | 194 | struct i915_ctx_workarounds wa_ctx; |
172 | 195 | ||
173 | unsigned irq_refcount; /* protected by dev_priv->irq_lock */ | 196 | u32 irq_keep_mask; /* always keep these interrupts */ |
174 | u32 irq_enable_mask; /* bitmask to enable ring interrupt */ | 197 | u32 irq_enable_mask; /* bitmask to enable ring interrupt */ |
175 | struct drm_i915_gem_request *trace_irq_req; | 198 | void (*irq_enable)(struct intel_engine_cs *ring); |
176 | bool __must_check (*irq_get)(struct intel_engine_cs *ring); | 199 | void (*irq_disable)(struct intel_engine_cs *ring); |
177 | void (*irq_put)(struct intel_engine_cs *ring); | ||
178 | 200 | ||
179 | int (*init_hw)(struct intel_engine_cs *ring); | 201 | int (*init_hw)(struct intel_engine_cs *ring); |
180 | 202 | ||
@@ -193,9 +215,6 @@ struct intel_engine_cs { | |||
193 | * monotonic, even if not coherent. | 215 | * monotonic, even if not coherent. |
194 | */ | 216 | */ |
195 | void (*irq_seqno_barrier)(struct intel_engine_cs *ring); | 217 | void (*irq_seqno_barrier)(struct intel_engine_cs *ring); |
196 | u32 (*get_seqno)(struct intel_engine_cs *ring); | ||
197 | void (*set_seqno)(struct intel_engine_cs *ring, | ||
198 | u32 seqno); | ||
199 | int (*dispatch_execbuffer)(struct drm_i915_gem_request *req, | 218 | int (*dispatch_execbuffer)(struct drm_i915_gem_request *req, |
200 | u64 offset, u32 length, | 219 | u64 offset, u32 length, |
201 | unsigned dispatch_flags); | 220 | unsigned dispatch_flags); |
@@ -272,7 +291,6 @@ struct intel_engine_cs { | |||
272 | unsigned int idle_lite_restore_wa; | 291 | unsigned int idle_lite_restore_wa; |
273 | bool disable_lite_restore_wa; | 292 | bool disable_lite_restore_wa; |
274 | u32 ctx_desc_template; | 293 | u32 ctx_desc_template; |
275 | u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */ | ||
276 | int (*emit_request)(struct drm_i915_gem_request *request); | 294 | int (*emit_request)(struct drm_i915_gem_request *request); |
277 | int (*emit_flush)(struct drm_i915_gem_request *request, | 295 | int (*emit_flush)(struct drm_i915_gem_request *request, |
278 | u32 invalidate_domains, | 296 | u32 invalidate_domains, |
@@ -304,12 +322,9 @@ struct intel_engine_cs { | |||
304 | * inspecting request list. | 322 | * inspecting request list. |
305 | */ | 323 | */ |
306 | u32 last_submitted_seqno; | 324 | u32 last_submitted_seqno; |
307 | unsigned user_interrupts; | ||
308 | 325 | ||
309 | bool gpu_caches_dirty; | 326 | bool gpu_caches_dirty; |
310 | 327 | ||
311 | wait_queue_head_t irq_queue; | ||
312 | |||
313 | struct i915_gem_context *last_context; | 328 | struct i915_gem_context *last_context; |
314 | 329 | ||
315 | struct intel_ring_hangcheck hangcheck; | 330 | struct intel_ring_hangcheck hangcheck; |
@@ -317,7 +332,6 @@ struct intel_engine_cs { | |||
317 | struct { | 332 | struct { |
318 | struct drm_i915_gem_object *obj; | 333 | struct drm_i915_gem_object *obj; |
319 | u32 gtt_offset; | 334 | u32 gtt_offset; |
320 | volatile u32 *cpu_page; | ||
321 | } scratch; | 335 | } scratch; |
322 | 336 | ||
323 | bool needs_cmd_parser; | 337 | bool needs_cmd_parser; |
@@ -348,13 +362,13 @@ struct intel_engine_cs { | |||
348 | }; | 362 | }; |
349 | 363 | ||
350 | static inline bool | 364 | static inline bool |
351 | intel_engine_initialized(struct intel_engine_cs *engine) | 365 | intel_engine_initialized(const struct intel_engine_cs *engine) |
352 | { | 366 | { |
353 | return engine->i915 != NULL; | 367 | return engine->i915 != NULL; |
354 | } | 368 | } |
355 | 369 | ||
356 | static inline unsigned | 370 | static inline unsigned |
357 | intel_engine_flag(struct intel_engine_cs *engine) | 371 | intel_engine_flag(const struct intel_engine_cs *engine) |
358 | { | 372 | { |
359 | return 1 << engine->id; | 373 | return 1 << engine->id; |
360 | } | 374 | } |
@@ -456,15 +470,14 @@ static inline void intel_ring_advance(struct intel_engine_cs *engine) | |||
456 | } | 470 | } |
457 | int __intel_ring_space(int head, int tail, int size); | 471 | int __intel_ring_space(int head, int tail, int size); |
458 | void intel_ring_update_space(struct intel_ringbuffer *ringbuf); | 472 | void intel_ring_update_space(struct intel_ringbuffer *ringbuf); |
459 | bool intel_engine_stopped(struct intel_engine_cs *engine); | ||
460 | 473 | ||
461 | int __must_check intel_engine_idle(struct intel_engine_cs *engine); | 474 | int __must_check intel_engine_idle(struct intel_engine_cs *engine); |
462 | void intel_ring_init_seqno(struct intel_engine_cs *engine, u32 seqno); | 475 | void intel_ring_init_seqno(struct intel_engine_cs *engine, u32 seqno); |
463 | int intel_ring_flush_all_caches(struct drm_i915_gem_request *req); | 476 | int intel_ring_flush_all_caches(struct drm_i915_gem_request *req); |
464 | int intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req); | 477 | int intel_ring_invalidate_all_caches(struct drm_i915_gem_request *req); |
465 | 478 | ||
479 | int intel_init_pipe_control(struct intel_engine_cs *engine, int size); | ||
466 | void intel_fini_pipe_control(struct intel_engine_cs *engine); | 480 | void intel_fini_pipe_control(struct intel_engine_cs *engine); |
467 | int intel_init_pipe_control(struct intel_engine_cs *engine); | ||
468 | 481 | ||
469 | int intel_init_render_ring_buffer(struct drm_device *dev); | 482 | int intel_init_render_ring_buffer(struct drm_device *dev); |
470 | int intel_init_bsd_ring_buffer(struct drm_device *dev); | 483 | int intel_init_bsd_ring_buffer(struct drm_device *dev); |
@@ -473,6 +486,10 @@ int intel_init_blt_ring_buffer(struct drm_device *dev); | |||
473 | int intel_init_vebox_ring_buffer(struct drm_device *dev); | 486 | int intel_init_vebox_ring_buffer(struct drm_device *dev); |
474 | 487 | ||
475 | u64 intel_ring_get_active_head(struct intel_engine_cs *engine); | 488 | u64 intel_ring_get_active_head(struct intel_engine_cs *engine); |
489 | static inline u32 intel_engine_get_seqno(struct intel_engine_cs *engine) | ||
490 | { | ||
491 | return intel_read_status_page(engine, I915_GEM_HWS_INDEX); | ||
492 | } | ||
476 | 493 | ||
477 | int init_workarounds_ring(struct intel_engine_cs *engine); | 494 | int init_workarounds_ring(struct intel_engine_cs *engine); |
478 | 495 | ||
@@ -495,4 +512,62 @@ static inline u32 intel_hws_seqno_address(struct intel_engine_cs *engine) | |||
495 | return engine->status_page.gfx_addr + I915_GEM_HWS_INDEX_ADDR; | 512 | return engine->status_page.gfx_addr + I915_GEM_HWS_INDEX_ADDR; |
496 | } | 513 | } |
497 | 514 | ||
515 | /* intel_breadcrumbs.c -- user interrupt bottom-half for waiters */ | ||
516 | struct intel_wait { | ||
517 | struct rb_node node; | ||
518 | struct task_struct *tsk; | ||
519 | u32 seqno; | ||
520 | }; | ||
521 | |||
522 | struct intel_signal_node { | ||
523 | struct rb_node node; | ||
524 | struct intel_wait wait; | ||
525 | }; | ||
526 | |||
527 | int intel_engine_init_breadcrumbs(struct intel_engine_cs *engine); | ||
528 | |||
529 | static inline void intel_wait_init(struct intel_wait *wait, u32 seqno) | ||
530 | { | ||
531 | wait->tsk = current; | ||
532 | wait->seqno = seqno; | ||
533 | } | ||
534 | |||
535 | static inline bool intel_wait_complete(const struct intel_wait *wait) | ||
536 | { | ||
537 | return RB_EMPTY_NODE(&wait->node); | ||
538 | } | ||
539 | |||
540 | bool intel_engine_add_wait(struct intel_engine_cs *engine, | ||
541 | struct intel_wait *wait); | ||
542 | void intel_engine_remove_wait(struct intel_engine_cs *engine, | ||
543 | struct intel_wait *wait); | ||
544 | void intel_engine_enable_signaling(struct drm_i915_gem_request *request); | ||
545 | |||
546 | static inline bool intel_engine_has_waiter(struct intel_engine_cs *engine) | ||
547 | { | ||
548 | return READ_ONCE(engine->breadcrumbs.irq_seqno_bh); | ||
549 | } | ||
550 | |||
551 | static inline bool intel_engine_wakeup(struct intel_engine_cs *engine) | ||
552 | { | ||
553 | bool wakeup = false; | ||
554 | struct task_struct *tsk = READ_ONCE(engine->breadcrumbs.irq_seqno_bh); | ||
555 | /* Note that for this not to dangerously chase a dangling pointer, | ||
556 | * the caller is responsible for ensure that the task remain valid for | ||
557 | * wake_up_process() i.e. that the RCU grace period cannot expire. | ||
558 | * | ||
559 | * Also note that tsk is likely to be in !TASK_RUNNING state so an | ||
560 | * early test for tsk->state != TASK_RUNNING before wake_up_process() | ||
561 | * is unlikely to be beneficial. | ||
562 | */ | ||
563 | if (tsk) | ||
564 | wakeup = wake_up_process(tsk); | ||
565 | return wakeup; | ||
566 | } | ||
567 | |||
568 | void intel_engine_enable_fake_irq(struct intel_engine_cs *engine); | ||
569 | void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine); | ||
570 | unsigned int intel_kick_waiters(struct drm_i915_private *i915); | ||
571 | unsigned int intel_kick_signalers(struct drm_i915_private *i915); | ||
572 | |||
498 | #endif /* _INTEL_RINGBUFFER_H_ */ | 573 | #endif /* _INTEL_RINGBUFFER_H_ */ |