on some stepping of SNB cpu, the first command to be parsed in BLT command streamer should be MI_BATCHBUFFER_START otherwise the GPU may hang.
Signed-off-by: Zou Nan hai <nanhai....@intel.com> --- drivers/gpu/drm/i915/intel_ringbuffer.c | 89 +++++++++++++++++++++++++++++- 1 files changed, 86 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 09f2dc3..4070f32 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -854,15 +854,98 @@ blt_ring_put_user_irq(struct drm_device *dev, /* do nothing */ } + +/* workaround for some stepping of SNB, + each time when BLT engine ring tail moved, + the first command in the ring to be parsed + should be MI_BATCH_BUFFER_START + */ +static struct drm_gem_object *wa_batch; +static unsigned long wa_batch_addr; + +#define NEED_BLT_WORKAROUND(dev) \ + (IS_GEN6(dev) && (dev->pdev->revision < 8)) + +static int blt_ring_init(struct drm_device *dev, + struct intel_ring_buffer *ring) +{ + u32 *ptr; + struct drm_i915_gem_object *batch; + if (NEED_BLT_WORKAROUND(dev) && wa_batch == NULL) { + wa_batch = i915_gem_alloc_object(dev, 4096); + + i915_gem_object_pin(wa_batch, 4096); + + batch = to_intel_bo(wa_batch); + wa_batch_addr = batch->gtt_offset; + + ptr = kmap(batch->pages[0]); + memset((u8 *)ptr, 0, 4096); + *ptr = MI_BATCH_BUFFER_END; + kunmap(batch->pages[0]); + } + return init_ring_common(dev, ring); +} + +static void blt_ring_flush(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 invalidate_domains, + u32 flush_domains) +{ + if (NEED_BLT_WORKAROUND(dev)) { + intel_ring_begin(dev, ring, 6); + intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START); + intel_ring_emit(dev, ring, wa_batch_addr); + } else + intel_ring_begin(dev, ring, 4); + + intel_ring_emit(dev, ring, MI_FLUSH_DW); + intel_ring_emit(dev, ring, 0); + intel_ring_emit(dev, ring, 0); + intel_ring_emit(dev, ring, 0); + + intel_ring_advance(dev, ring); +} + +static u32 +blt_ring_add_request(struct drm_device *dev, + struct intel_ring_buffer *ring, + u32 flush_domains) +{ + u32 seqno; + + seqno = i915_gem_get_seqno(dev); + + if (NEED_BLT_WORKAROUND(dev)) { + intel_ring_begin(dev, ring, 6); + intel_ring_emit(dev, ring, MI_BATCH_BUFFER_START); + intel_ring_emit(dev, ring, wa_batch_addr); + } else { + intel_ring_begin(dev, ring, 4); + } + + intel_ring_emit(dev, ring, MI_STORE_DWORD_INDEX); + intel_ring_emit(dev, ring, + I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); + intel_ring_emit(dev, ring, seqno); + intel_ring_emit(dev, ring, MI_USER_INTERRUPT); + + intel_ring_advance(dev, ring); + + DRM_DEBUG_DRIVER("%s %d\n", ring->name, seqno); + + return seqno; +} + static const struct intel_ring_buffer gen6_blt_ring = { .name = "blt ring", .id = RING_BLT, .mmio_base = BLT_RING_BASE, .size = 32 * PAGE_SIZE, - .init = init_ring_common, + .init = blt_ring_init, .write_tail = ring_write_tail, - .flush = gen6_ring_flush, - .add_request = ring_add_request, + .flush = blt_ring_flush, + .add_request = blt_ring_add_request, .get_seqno = ring_status_page_get_seqno, .user_irq_get = blt_ring_get_user_irq, .user_irq_put = blt_ring_put_user_irq, -- 1.7.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/intel-gfx