aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_ringbuffer.c
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2019-01-25 08:22:28 -0500
committerChris Wilson <chris@chris-wilson.co.uk>2019-01-25 09:27:22 -0500
commiteb8d0f5af4ec2d172baf8b4b9a2199cd916b4e54 (patch)
tree28293a5cdfd09863ce764d181c5039cce25b79a2 /drivers/gpu/drm/i915/intel_ringbuffer.c
parentfe62365f9f80a1c1d438c54fba21f5108a182de8 (diff)
drm/i915: Remove GPU reset dependence on struct_mutex
Now that the submission backends are controlled via their own spinlocks, with a wave of a magic wand we can lift the struct_mutex requirement around GPU reset. That is we allow the submission frontend (userspace) to keep on submitting while we process the GPU reset as we can suspend the backend independently. The major change is around the backoff/handoff strategy for performing the reset. With no mutex deadlock, we no longer have to coordinate with any waiter, and just perform the reset immediately. Testcase: igt/gem_mmap_gtt/hang # regresses Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Reviewed-by: Mika Kuoppala <mika.kuoppala@linux.intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20190125132230.22221-3-chris@chris-wilson.co.uk
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ringbuffer.c')
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c91
1 files changed, 60 insertions, 31 deletions
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 09c90475168a..a9efc8c71254 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -33,6 +33,7 @@
33 33
34#include "i915_drv.h" 34#include "i915_drv.h"
35#include "i915_gem_render_state.h" 35#include "i915_gem_render_state.h"
36#include "i915_reset.h"
36#include "i915_trace.h" 37#include "i915_trace.h"
37#include "intel_drv.h" 38#include "intel_drv.h"
38#include "intel_workarounds.h" 39#include "intel_workarounds.h"
@@ -711,52 +712,80 @@ out:
711 return ret; 712 return ret;
712} 713}
713 714
714static struct i915_request *reset_prepare(struct intel_engine_cs *engine) 715static void reset_prepare(struct intel_engine_cs *engine)
715{ 716{
716 intel_engine_stop_cs(engine); 717 intel_engine_stop_cs(engine);
717 return i915_gem_find_active_request(engine);
718} 718}
719 719
720static void skip_request(struct i915_request *rq) 720static void reset_ring(struct intel_engine_cs *engine, bool stalled)
721{ 721{
722 void *vaddr = rq->ring->vaddr; 722 struct i915_timeline *tl = &engine->timeline;
723 struct i915_request *pos, *rq;
724 unsigned long flags;
723 u32 head; 725 u32 head;
724 726
725 head = rq->infix; 727 rq = NULL;
726 if (rq->postfix < head) { 728 spin_lock_irqsave(&tl->lock, flags);
727 memset32(vaddr + head, MI_NOOP, 729 list_for_each_entry(pos, &tl->requests, link) {
728 (rq->ring->size - head) / sizeof(u32)); 730 if (!__i915_request_completed(pos, pos->global_seqno)) {
729 head = 0; 731 rq = pos;
732 break;
733 }
730 } 734 }
731 memset32(vaddr + head, MI_NOOP, (rq->postfix - head) / sizeof(u32));
732}
733
734static void reset_ring(struct intel_engine_cs *engine, struct i915_request *rq)
735{
736 GEM_TRACE("%s request global=%d, current=%d\n",
737 engine->name, rq ? rq->global_seqno : 0,
738 intel_engine_get_seqno(engine));
739 735
736 GEM_TRACE("%s seqno=%d, current=%d, stalled? %s\n",
737 engine->name,
738 rq ? rq->global_seqno : 0,
739 intel_engine_get_seqno(engine),
740 yesno(stalled));
740 /* 741 /*
741 * Try to restore the logical GPU state to match the continuation 742 * The guilty request will get skipped on a hung engine.
742 * of the request queue. If we skip the context/PD restore, then
743 * the next request may try to execute assuming that its context
744 * is valid and loaded on the GPU and so may try to access invalid
745 * memory, prompting repeated GPU hangs.
746 * 743 *
747 * If the request was guilty, we still restore the logical state 744 * Users of client default contexts do not rely on logical
748 * in case the next request requires it (e.g. the aliasing ppgtt), 745 * state preserved between batches so it is safe to execute
749 * but skip over the hung batch. 746 * queued requests following the hang. Non default contexts
747 * rely on preserved state, so skipping a batch loses the
748 * evolution of the state and it needs to be considered corrupted.
749 * Executing more queued batches on top of corrupted state is
750 * risky. But we take the risk by trying to advance through
751 * the queued requests in order to make the client behaviour
752 * more predictable around resets, by not throwing away random
753 * amount of batches it has prepared for execution. Sophisticated
754 * clients can use gem_reset_stats_ioctl and dma fence status
755 * (exported via sync_file info ioctl on explicit fences) to observe
756 * when it loses the context state and should rebuild accordingly.
750 * 757 *
751 * If the request was innocent, we try to replay the request with 758 * The context ban, and ultimately the client ban, mechanism are safety
752 * the restored context. 759 * valves if client submission ends up resulting in nothing more than
760 * subsequent hangs.
753 */ 761 */
762
754 if (rq) { 763 if (rq) {
755 /* If the rq hung, jump to its breadcrumb and skip the batch */ 764 /*
756 rq->ring->head = intel_ring_wrap(rq->ring, rq->head); 765 * Try to restore the logical GPU state to match the
757 if (rq->fence.error == -EIO) 766 * continuation of the request queue. If we skip the
758 skip_request(rq); 767 * context/PD restore, then the next request may try to execute
768 * assuming that its context is valid and loaded on the GPU and
769 * so may try to access invalid memory, prompting repeated GPU
770 * hangs.
771 *
772 * If the request was guilty, we still restore the logical
773 * state in case the next request requires it (e.g. the
774 * aliasing ppgtt), but skip over the hung batch.
775 *
776 * If the request was innocent, we try to replay the request
777 * with the restored context.
778 */
779 i915_reset_request(rq, stalled);
780
781 GEM_BUG_ON(rq->ring != engine->buffer);
782 head = rq->head;
783 } else {
784 head = engine->buffer->tail;
759 } 785 }
786 engine->buffer->head = intel_ring_wrap(engine->buffer, head);
787
788 spin_unlock_irqrestore(&tl->lock, flags);
760} 789}
761 790
762static void reset_finish(struct intel_engine_cs *engine) 791static void reset_finish(struct intel_engine_cs *engine)