Message ID | 1443446247-13837-1-git-send-email-michel.thierry@intel.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Michel Thierry <michel.thierry@intel.com> writes: > A previous commit resets the Context Status Buffer (CSB) read pointer in > ring init > commit c0a03a2e4c4e ("drm/i915: Reset CSB read pointer in ring init") > > This is generally correct, but this pointer is not reset after > suspend/resume in some platforms (cht). In this case, the driver should > read the register value instead of resetting the sw read counter to 0. > Otherwise we process old events, leading to unwanted pre-emptions or > something worse. > > But in other platforms (bdw) and also during GPU reset or power up, the > CSBWP is reset to 0x7 (an invalid number), and in this case the read > pointer should be set to 5 (the interrupt code will increment this > counter one more time, and will start reading from CSB[0]). > > v2: When the CSB registers are reset, the read pointer needs to be set > to 5, otherwise the first write (CSB[0]) won't be read (Mika). > Replace magic numbers with GEN8_CSB_ENTRIES (6) and GEN8_CSB_PTR_MASK > (0x07). > v3: Rebased on top of "Parametrize LRC registers" patch. > > Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> > Signed-off-by: Lei Shen <lei.shen@intel.com> > Signed-off-by: Deepak S <deepak.s@intel.com> > Signed-off-by: Michel Thierry <michel.thierry@intel.com> > --- > drivers/gpu/drm/i915/intel_lrc.c | 39 ++++++++++++++++++++++++++++++++------- > drivers/gpu/drm/i915/intel_lrc.h | 2 ++ > 2 files changed, 34 insertions(+), 7 deletions(-) > > diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c > index 256167b..825fa7a 100644 > --- a/drivers/gpu/drm/i915/intel_lrc.c > +++ b/drivers/gpu/drm/i915/intel_lrc.c > @@ -511,16 +511,16 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) > status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring)); > > read_pointer = ring->next_context_status_buffer; > - write_pointer = status_pointer & 0x07; > + write_pointer = status_pointer & GEN8_CSB_PTR_MASK; > if (read_pointer > write_pointer) > - write_pointer += 6; > + write_pointer += GEN8_CSB_ENTRIES; > > spin_lock(&ring->execlist_lock); > > while (read_pointer < write_pointer) { > read_pointer++; > - status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % 6)); > - status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % 6)); > + status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % GEN8_CSB_ENTRIES)); > + status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % GEN8_CSB_ENTRIES)); > > if (status & GEN8_CTX_STATUS_IDLE_ACTIVE) > continue; > @@ -552,10 +552,12 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) > spin_unlock(&ring->execlist_lock); > > WARN(submit_contexts > 2, "More than two context complete events?\n"); > - ring->next_context_status_buffer = write_pointer % 6; > + ring->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES; > > I915_WRITE(RING_CONTEXT_STATUS_PTR(ring), > - _MASKED_FIELD(0x07 << 8, ((u32)ring->next_context_status_buffer & 0x07) << 8)); > + _MASKED_FIELD(GEN8_CSB_PTR_MASK << 8, > + ((u32)ring->next_context_status_buffer & > + GEN8_CSB_PTR_MASK) << 8)); > } > > static int execlists_context_queue(struct drm_i915_gem_request *request) > @@ -1477,6 +1479,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) > { > struct drm_device *dev = ring->dev; > struct drm_i915_private *dev_priv = dev->dev_private; > + u8 next_context_status_buffer_hw; > > lrc_setup_hardware_status_page(ring, > ring->default_context->engine[ring->id].state); > @@ -1494,7 +1497,29 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) > _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | > _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); > POSTING_READ(RING_MODE_GEN7(ring)); > - ring->next_context_status_buffer = 0; > + > + /* > + * Instead of resetting the Context Status Buffer (CSB) read pointer to > + * zero, we need to read the write pointer from hardware and use its > + * value because "this register is power context save restored". > + * Effectively, these states have been observed: > + * > + * | Suspend-to-idle (freeze) | Suspend-to-RAM (mem) | > + * BDW | CSB regs not reset | CSB regs reset | > + * CHT | CSB regs not reset | CSB regs not reset | > + */ SKL acts similar to BDW. > + next_context_status_buffer_hw = (I915_READ(RING_CONTEXT_STATUS_PTR(ring)) > + & GEN8_CSB_PTR_MASK); > + > + /* > + * When the CSB registers are reset (also after power-up / gpu reset), > + * CSB write pointer is set to all 1's, which is not valid, use '5' in > + * this special case, so the first element read is CSB[0]. > + */ > + if (next_context_status_buffer_hw == GEN8_CSB_PTR_MASK) > + next_context_status_buffer_hw = (GEN8_CSB_ENTRIES - 1); > + Now that this has been unravelled, I hope we can move towards of removing the driver state of next context buffer completely: http://lists.freedesktop.org/archives/intel-gfx/2015-May/067313.html Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> > + ring->next_context_status_buffer = next_context_status_buffer_hw; > DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name); > > memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); > diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h > index 8a08a27..4e60d54 100644 > --- a/drivers/gpu/drm/i915/intel_lrc.h > +++ b/drivers/gpu/drm/i915/intel_lrc.h > @@ -25,6 +25,8 @@ > #define _INTEL_LRC_H_ > > #define GEN8_LR_CONTEXT_ALIGN 4096 > +#define GEN8_CSB_ENTRIES 6 > +#define GEN8_CSB_PTR_MASK 0x07 > > /* Execlists regs */ > #define RING_ELSP(ring) ((ring)->mmio_base+0x230) > -- > 2.5.3
On Mon, Sep 28, 2015 at 05:00:12PM +0300, Mika Kuoppala wrote: > Michel Thierry <michel.thierry@intel.com> writes: > > > A previous commit resets the Context Status Buffer (CSB) read pointer in > > ring init > > commit c0a03a2e4c4e ("drm/i915: Reset CSB read pointer in ring init") This is in 4.0, so Cc: stable@vger.kernel.org and one for Jani. -Daniel > > > > This is generally correct, but this pointer is not reset after > > suspend/resume in some platforms (cht). In this case, the driver should > > read the register value instead of resetting the sw read counter to 0. > > Otherwise we process old events, leading to unwanted pre-emptions or > > something worse. > > > > But in other platforms (bdw) and also during GPU reset or power up, the > > CSBWP is reset to 0x7 (an invalid number), and in this case the read > > pointer should be set to 5 (the interrupt code will increment this > > counter one more time, and will start reading from CSB[0]). > > > > v2: When the CSB registers are reset, the read pointer needs to be set > > to 5, otherwise the first write (CSB[0]) won't be read (Mika). > > Replace magic numbers with GEN8_CSB_ENTRIES (6) and GEN8_CSB_PTR_MASK > > (0x07). > > v3: Rebased on top of "Parametrize LRC registers" patch. > > > > Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> > > Signed-off-by: Lei Shen <lei.shen@intel.com> > > Signed-off-by: Deepak S <deepak.s@intel.com> > > Signed-off-by: Michel Thierry <michel.thierry@intel.com> > > --- > > drivers/gpu/drm/i915/intel_lrc.c | 39 ++++++++++++++++++++++++++++++++------- > > drivers/gpu/drm/i915/intel_lrc.h | 2 ++ > > 2 files changed, 34 insertions(+), 7 deletions(-) > > > > diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c > > index 256167b..825fa7a 100644 > > --- a/drivers/gpu/drm/i915/intel_lrc.c > > +++ b/drivers/gpu/drm/i915/intel_lrc.c > > @@ -511,16 +511,16 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) > > status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring)); > > > > read_pointer = ring->next_context_status_buffer; > > - write_pointer = status_pointer & 0x07; > > + write_pointer = status_pointer & GEN8_CSB_PTR_MASK; > > if (read_pointer > write_pointer) > > - write_pointer += 6; > > + write_pointer += GEN8_CSB_ENTRIES; > > > > spin_lock(&ring->execlist_lock); > > > > while (read_pointer < write_pointer) { > > read_pointer++; > > - status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % 6)); > > - status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % 6)); > > + status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % GEN8_CSB_ENTRIES)); > > + status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % GEN8_CSB_ENTRIES)); > > > > if (status & GEN8_CTX_STATUS_IDLE_ACTIVE) > > continue; > > @@ -552,10 +552,12 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) > > spin_unlock(&ring->execlist_lock); > > > > WARN(submit_contexts > 2, "More than two context complete events?\n"); > > - ring->next_context_status_buffer = write_pointer % 6; > > + ring->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES; > > > > I915_WRITE(RING_CONTEXT_STATUS_PTR(ring), > > - _MASKED_FIELD(0x07 << 8, ((u32)ring->next_context_status_buffer & 0x07) << 8)); > > + _MASKED_FIELD(GEN8_CSB_PTR_MASK << 8, > > + ((u32)ring->next_context_status_buffer & > > + GEN8_CSB_PTR_MASK) << 8)); > > } > > > > static int execlists_context_queue(struct drm_i915_gem_request *request) > > @@ -1477,6 +1479,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) > > { > > struct drm_device *dev = ring->dev; > > struct drm_i915_private *dev_priv = dev->dev_private; > > + u8 next_context_status_buffer_hw; > > > > lrc_setup_hardware_status_page(ring, > > ring->default_context->engine[ring->id].state); > > @@ -1494,7 +1497,29 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) > > _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | > > _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); > > POSTING_READ(RING_MODE_GEN7(ring)); > > - ring->next_context_status_buffer = 0; > > + > > + /* > > + * Instead of resetting the Context Status Buffer (CSB) read pointer to > > + * zero, we need to read the write pointer from hardware and use its > > + * value because "this register is power context save restored". > > + * Effectively, these states have been observed: > > + * > > + * | Suspend-to-idle (freeze) | Suspend-to-RAM (mem) | > > + * BDW | CSB regs not reset | CSB regs reset | > > + * CHT | CSB regs not reset | CSB regs not reset | > > + */ > > SKL acts similar to BDW. > > > + next_context_status_buffer_hw = (I915_READ(RING_CONTEXT_STATUS_PTR(ring)) > > + & GEN8_CSB_PTR_MASK); > > + > > + /* > > + * When the CSB registers are reset (also after power-up / gpu reset), > > + * CSB write pointer is set to all 1's, which is not valid, use '5' in > > + * this special case, so the first element read is CSB[0]. > > + */ > > + if (next_context_status_buffer_hw == GEN8_CSB_PTR_MASK) > > + next_context_status_buffer_hw = (GEN8_CSB_ENTRIES - 1); > > + > > Now that this has been unravelled, I hope we can move towards > of removing the driver state of next context buffer completely: > > http://lists.freedesktop.org/archives/intel-gfx/2015-May/067313.html > > Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> > > > + ring->next_context_status_buffer = next_context_status_buffer_hw; > > DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name); > > > > memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); > > diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h > > index 8a08a27..4e60d54 100644 > > --- a/drivers/gpu/drm/i915/intel_lrc.h > > +++ b/drivers/gpu/drm/i915/intel_lrc.h > > @@ -25,6 +25,8 @@ > > #define _INTEL_LRC_H_ > > > > #define GEN8_LR_CONTEXT_ALIGN 4096 > > +#define GEN8_CSB_ENTRIES 6 > > +#define GEN8_CSB_PTR_MASK 0x07 > > > > /* Execlists regs */ > > #define RING_ELSP(ring) ((ring)->mmio_base+0x230) > > -- > > 2.5.3 > > > > _______________________________________________ > Intel-gfx mailing list > Intel-gfx@lists.freedesktop.org > http://lists.freedesktop.org/mailman/listinfo/intel-gfx
On Mon, 28 Sep 2015, Daniel Vetter <daniel@ffwll.ch> wrote: > On Mon, Sep 28, 2015 at 05:00:12PM +0300, Mika Kuoppala wrote: >> Michel Thierry <michel.thierry@intel.com> writes: >> >> > A previous commit resets the Context Status Buffer (CSB) read pointer in >> > ring init >> > commit c0a03a2e4c4e ("drm/i915: Reset CSB read pointer in ring init") > > This is in 4.0, so Cc: stable@vger.kernel.org and one for Jani. > -Daniel > >> > >> > This is generally correct, but this pointer is not reset after >> > suspend/resume in some platforms (cht). In this case, the driver should >> > read the register value instead of resetting the sw read counter to 0. >> > Otherwise we process old events, leading to unwanted pre-emptions or >> > something worse. >> > >> > But in other platforms (bdw) and also during GPU reset or power up, the >> > CSBWP is reset to 0x7 (an invalid number), and in this case the read >> > pointer should be set to 5 (the interrupt code will increment this >> > counter one more time, and will start reading from CSB[0]). >> > >> > v2: When the CSB registers are reset, the read pointer needs to be set >> > to 5, otherwise the first write (CSB[0]) won't be read (Mika). >> > Replace magic numbers with GEN8_CSB_ENTRIES (6) and GEN8_CSB_PTR_MASK >> > (0x07). >> > v3: Rebased on top of "Parametrize LRC registers" patch. Pushed v2 to drm-intel-fixes, as that branch doesn't have the "Parametrize LRC registers" patch, thanks for the patch and review. BR, Jani. >> > >> > Cc: Mika Kuoppala <mika.kuoppala@linux.intel.com> >> > Signed-off-by: Lei Shen <lei.shen@intel.com> >> > Signed-off-by: Deepak S <deepak.s@intel.com> >> > Signed-off-by: Michel Thierry <michel.thierry@intel.com> >> > --- >> > drivers/gpu/drm/i915/intel_lrc.c | 39 ++++++++++++++++++++++++++++++++------- >> > drivers/gpu/drm/i915/intel_lrc.h | 2 ++ >> > 2 files changed, 34 insertions(+), 7 deletions(-) >> > >> > diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c >> > index 256167b..825fa7a 100644 >> > --- a/drivers/gpu/drm/i915/intel_lrc.c >> > +++ b/drivers/gpu/drm/i915/intel_lrc.c >> > @@ -511,16 +511,16 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) >> > status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring)); >> > >> > read_pointer = ring->next_context_status_buffer; >> > - write_pointer = status_pointer & 0x07; >> > + write_pointer = status_pointer & GEN8_CSB_PTR_MASK; >> > if (read_pointer > write_pointer) >> > - write_pointer += 6; >> > + write_pointer += GEN8_CSB_ENTRIES; >> > >> > spin_lock(&ring->execlist_lock); >> > >> > while (read_pointer < write_pointer) { >> > read_pointer++; >> > - status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % 6)); >> > - status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % 6)); >> > + status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % GEN8_CSB_ENTRIES)); >> > + status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % GEN8_CSB_ENTRIES)); >> > >> > if (status & GEN8_CTX_STATUS_IDLE_ACTIVE) >> > continue; >> > @@ -552,10 +552,12 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) >> > spin_unlock(&ring->execlist_lock); >> > >> > WARN(submit_contexts > 2, "More than two context complete events?\n"); >> > - ring->next_context_status_buffer = write_pointer % 6; >> > + ring->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES; >> > >> > I915_WRITE(RING_CONTEXT_STATUS_PTR(ring), >> > - _MASKED_FIELD(0x07 << 8, ((u32)ring->next_context_status_buffer & 0x07) << 8)); >> > + _MASKED_FIELD(GEN8_CSB_PTR_MASK << 8, >> > + ((u32)ring->next_context_status_buffer & >> > + GEN8_CSB_PTR_MASK) << 8)); >> > } >> > >> > static int execlists_context_queue(struct drm_i915_gem_request *request) >> > @@ -1477,6 +1479,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) >> > { >> > struct drm_device *dev = ring->dev; >> > struct drm_i915_private *dev_priv = dev->dev_private; >> > + u8 next_context_status_buffer_hw; >> > >> > lrc_setup_hardware_status_page(ring, >> > ring->default_context->engine[ring->id].state); >> > @@ -1494,7 +1497,29 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) >> > _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | >> > _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); >> > POSTING_READ(RING_MODE_GEN7(ring)); >> > - ring->next_context_status_buffer = 0; >> > + >> > + /* >> > + * Instead of resetting the Context Status Buffer (CSB) read pointer to >> > + * zero, we need to read the write pointer from hardware and use its >> > + * value because "this register is power context save restored". >> > + * Effectively, these states have been observed: >> > + * >> > + * | Suspend-to-idle (freeze) | Suspend-to-RAM (mem) | >> > + * BDW | CSB regs not reset | CSB regs reset | >> > + * CHT | CSB regs not reset | CSB regs not reset | >> > + */ >> >> SKL acts similar to BDW. >> >> > + next_context_status_buffer_hw = (I915_READ(RING_CONTEXT_STATUS_PTR(ring)) >> > + & GEN8_CSB_PTR_MASK); >> > + >> > + /* >> > + * When the CSB registers are reset (also after power-up / gpu reset), >> > + * CSB write pointer is set to all 1's, which is not valid, use '5' in >> > + * this special case, so the first element read is CSB[0]. >> > + */ >> > + if (next_context_status_buffer_hw == GEN8_CSB_PTR_MASK) >> > + next_context_status_buffer_hw = (GEN8_CSB_ENTRIES - 1); >> > + >> >> Now that this has been unravelled, I hope we can move towards >> of removing the driver state of next context buffer completely: >> >> http://lists.freedesktop.org/archives/intel-gfx/2015-May/067313.html >> >> Reviewed-by: Mika Kuoppala <mika.kuoppala@intel.com> >> >> > + ring->next_context_status_buffer = next_context_status_buffer_hw; >> > DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name); >> > >> > memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); >> > diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h >> > index 8a08a27..4e60d54 100644 >> > --- a/drivers/gpu/drm/i915/intel_lrc.h >> > +++ b/drivers/gpu/drm/i915/intel_lrc.h >> > @@ -25,6 +25,8 @@ >> > #define _INTEL_LRC_H_ >> > >> > #define GEN8_LR_CONTEXT_ALIGN 4096 >> > +#define GEN8_CSB_ENTRIES 6 >> > +#define GEN8_CSB_PTR_MASK 0x07 >> > >> > /* Execlists regs */ >> > #define RING_ELSP(ring) ((ring)->mmio_base+0x230) >> > -- >> > 2.5.3 >> >> >> >> _______________________________________________ >> Intel-gfx mailing list >> Intel-gfx@lists.freedesktop.org >> http://lists.freedesktop.org/mailman/listinfo/intel-gfx > > -- > Daniel Vetter > Software Engineer, Intel Corporation > http://blog.ffwll.ch
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c index 256167b..825fa7a 100644 --- a/drivers/gpu/drm/i915/intel_lrc.c +++ b/drivers/gpu/drm/i915/intel_lrc.c @@ -511,16 +511,16 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring)); read_pointer = ring->next_context_status_buffer; - write_pointer = status_pointer & 0x07; + write_pointer = status_pointer & GEN8_CSB_PTR_MASK; if (read_pointer > write_pointer) - write_pointer += 6; + write_pointer += GEN8_CSB_ENTRIES; spin_lock(&ring->execlist_lock); while (read_pointer < write_pointer) { read_pointer++; - status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % 6)); - status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % 6)); + status = I915_READ(RING_CONTEXT_STATUS_BUF_LO(ring, read_pointer % GEN8_CSB_ENTRIES)); + status_id = I915_READ(RING_CONTEXT_STATUS_BUF_HI(ring, read_pointer % GEN8_CSB_ENTRIES)); if (status & GEN8_CTX_STATUS_IDLE_ACTIVE) continue; @@ -552,10 +552,12 @@ void intel_lrc_irq_handler(struct intel_engine_cs *ring) spin_unlock(&ring->execlist_lock); WARN(submit_contexts > 2, "More than two context complete events?\n"); - ring->next_context_status_buffer = write_pointer % 6; + ring->next_context_status_buffer = write_pointer % GEN8_CSB_ENTRIES; I915_WRITE(RING_CONTEXT_STATUS_PTR(ring), - _MASKED_FIELD(0x07 << 8, ((u32)ring->next_context_status_buffer & 0x07) << 8)); + _MASKED_FIELD(GEN8_CSB_PTR_MASK << 8, + ((u32)ring->next_context_status_buffer & + GEN8_CSB_PTR_MASK) << 8)); } static int execlists_context_queue(struct drm_i915_gem_request *request) @@ -1477,6 +1479,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) { struct drm_device *dev = ring->dev; struct drm_i915_private *dev_priv = dev->dev_private; + u8 next_context_status_buffer_hw; lrc_setup_hardware_status_page(ring, ring->default_context->engine[ring->id].state); @@ -1494,7 +1497,29 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring) _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) | _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE)); POSTING_READ(RING_MODE_GEN7(ring)); - ring->next_context_status_buffer = 0; + + /* + * Instead of resetting the Context Status Buffer (CSB) read pointer to + * zero, we need to read the write pointer from hardware and use its + * value because "this register is power context save restored". + * Effectively, these states have been observed: + * + * | Suspend-to-idle (freeze) | Suspend-to-RAM (mem) | + * BDW | CSB regs not reset | CSB regs reset | + * CHT | CSB regs not reset | CSB regs not reset | + */ + next_context_status_buffer_hw = (I915_READ(RING_CONTEXT_STATUS_PTR(ring)) + & GEN8_CSB_PTR_MASK); + + /* + * When the CSB registers are reset (also after power-up / gpu reset), + * CSB write pointer is set to all 1's, which is not valid, use '5' in + * this special case, so the first element read is CSB[0]. + */ + if (next_context_status_buffer_hw == GEN8_CSB_PTR_MASK) + next_context_status_buffer_hw = (GEN8_CSB_ENTRIES - 1); + + ring->next_context_status_buffer = next_context_status_buffer_hw; DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name); memset(&ring->hangcheck, 0, sizeof(ring->hangcheck)); diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h index 8a08a27..4e60d54 100644 --- a/drivers/gpu/drm/i915/intel_lrc.h +++ b/drivers/gpu/drm/i915/intel_lrc.h @@ -25,6 +25,8 @@ #define _INTEL_LRC_H_ #define GEN8_LR_CONTEXT_ALIGN 4096 +#define GEN8_CSB_ENTRIES 6 +#define GEN8_CSB_PTR_MASK 0x07 /* Execlists regs */ #define RING_ELSP(ring) ((ring)->mmio_base+0x230)