mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-14 12:37:32 +00:00
drm/i915: Wrap around the tail offset before setting ring->tail
The HW only accepts offsets within ring->size, and fails peculiarly if the RING_HEAD or RING_TAIL is set to ring->size. Therefore whenever we set ring->head/ring->tail we want to make sure it is within value (using intel_ring_wrap()). v2: Double check execlists as well v3: Remove redundancy with assert_ring_tail_valid() v4: Just assert in intel_ring_reset() rather than be over-defensive. Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk> Cc: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> Cc: Matthew Auld <matthew.william.auld@gmail.com> Cc: Tvrtko Ursulin <tvrtko.ursulin@intel.com> Reviewed-by: Joonas Lahtinen <joonas.lahtinen@linux.intel.com> #v2 Link: https://patchwork.freedesktop.org/patch/msgid/20180611110845.31890-2-chris@chris-wilson.co.uk
This commit is contained in:
parent
b3ee09a4de
commit
41d37680ca
3 changed files with 24 additions and 8 deletions
|
@ -1414,6 +1414,7 @@ __execlists_context_pin(struct intel_engine_cs *engine,
|
||||||
ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE;
|
ce->lrc_reg_state = vaddr + LRC_STATE_PN * PAGE_SIZE;
|
||||||
ce->lrc_reg_state[CTX_RING_BUFFER_START+1] =
|
ce->lrc_reg_state[CTX_RING_BUFFER_START+1] =
|
||||||
i915_ggtt_offset(ce->ring->vma);
|
i915_ggtt_offset(ce->ring->vma);
|
||||||
|
GEM_BUG_ON(!intel_ring_offset_valid(ce->ring, ce->ring->head));
|
||||||
ce->lrc_reg_state[CTX_RING_HEAD+1] = ce->ring->head;
|
ce->lrc_reg_state[CTX_RING_HEAD+1] = ce->ring->head;
|
||||||
|
|
||||||
ce->state->obj->pin_global++;
|
ce->state->obj->pin_global++;
|
||||||
|
@ -2002,9 +2003,10 @@ static void execlists_reset(struct intel_engine_cs *engine,
|
||||||
|
|
||||||
/* Move the RING_HEAD onto the breadcrumb, past the hanging batch */
|
/* Move the RING_HEAD onto the breadcrumb, past the hanging batch */
|
||||||
regs[CTX_RING_BUFFER_START + 1] = i915_ggtt_offset(request->ring->vma);
|
regs[CTX_RING_BUFFER_START + 1] = i915_ggtt_offset(request->ring->vma);
|
||||||
regs[CTX_RING_HEAD + 1] = request->postfix;
|
|
||||||
|
|
||||||
request->ring->head = request->postfix;
|
request->ring->head = intel_ring_wrap(request->ring, request->postfix);
|
||||||
|
regs[CTX_RING_HEAD + 1] = request->ring->head;
|
||||||
|
|
||||||
intel_ring_update_space(request->ring);
|
intel_ring_update_space(request->ring);
|
||||||
|
|
||||||
/* Reset WaIdleLiteRestore:bdw,skl as well */
|
/* Reset WaIdleLiteRestore:bdw,skl as well */
|
||||||
|
|
|
@ -496,6 +496,10 @@ static int init_ring_common(struct intel_engine_cs *engine)
|
||||||
DRM_DEBUG_DRIVER("%s initialization failed [head=%08x], fudging\n",
|
DRM_DEBUG_DRIVER("%s initialization failed [head=%08x], fudging\n",
|
||||||
engine->name, I915_READ_HEAD(engine));
|
engine->name, I915_READ_HEAD(engine));
|
||||||
|
|
||||||
|
/* Check that the ring offsets point within the ring! */
|
||||||
|
GEM_BUG_ON(!intel_ring_offset_valid(ring, ring->head));
|
||||||
|
GEM_BUG_ON(!intel_ring_offset_valid(ring, ring->tail));
|
||||||
|
|
||||||
intel_ring_update_space(ring);
|
intel_ring_update_space(ring);
|
||||||
I915_WRITE_HEAD(engine, ring->head);
|
I915_WRITE_HEAD(engine, ring->head);
|
||||||
I915_WRITE_TAIL(engine, ring->tail);
|
I915_WRITE_TAIL(engine, ring->tail);
|
||||||
|
@ -1062,6 +1066,8 @@ int intel_ring_pin(struct intel_ring *ring,
|
||||||
|
|
||||||
void intel_ring_reset(struct intel_ring *ring, u32 tail)
|
void intel_ring_reset(struct intel_ring *ring, u32 tail)
|
||||||
{
|
{
|
||||||
|
GEM_BUG_ON(!intel_ring_offset_valid(ring, tail));
|
||||||
|
|
||||||
ring->tail = tail;
|
ring->tail = tail;
|
||||||
ring->head = tail;
|
ring->head = tail;
|
||||||
ring->emit = tail;
|
ring->emit = tail;
|
||||||
|
|
|
@ -805,6 +805,19 @@ static inline u32 intel_ring_wrap(const struct intel_ring *ring, u32 pos)
|
||||||
return pos & (ring->size - 1);
|
return pos & (ring->size - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool
|
||||||
|
intel_ring_offset_valid(const struct intel_ring *ring,
|
||||||
|
unsigned int pos)
|
||||||
|
{
|
||||||
|
if (pos & -ring->size) /* must be strictly within the ring */
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!IS_ALIGNED(pos, 8)) /* must be qword aligned */
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static inline u32 intel_ring_offset(const struct i915_request *rq, void *addr)
|
static inline u32 intel_ring_offset(const struct i915_request *rq, void *addr)
|
||||||
{
|
{
|
||||||
/* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
|
/* Don't write ring->size (equivalent to 0) as that hangs some GPUs. */
|
||||||
|
@ -816,12 +829,7 @@ static inline u32 intel_ring_offset(const struct i915_request *rq, void *addr)
|
||||||
static inline void
|
static inline void
|
||||||
assert_ring_tail_valid(const struct intel_ring *ring, unsigned int tail)
|
assert_ring_tail_valid(const struct intel_ring *ring, unsigned int tail)
|
||||||
{
|
{
|
||||||
/* We could combine these into a single tail operation, but keeping
|
GEM_BUG_ON(!intel_ring_offset_valid(ring, tail));
|
||||||
* them as seperate tests will help identify the cause should one
|
|
||||||
* ever fire.
|
|
||||||
*/
|
|
||||||
GEM_BUG_ON(!IS_ALIGNED(tail, 8));
|
|
||||||
GEM_BUG_ON(tail >= ring->size);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "Ring Buffer Use"
|
* "Ring Buffer Use"
|
||||||
|
|
Loading…
Reference in a new issue