diff options
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ringbuffer.c')
-rw-r--r-- | drivers/gpu/drm/i915/intel_ringbuffer.c | 222 |
1 files changed, 98 insertions, 124 deletions
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c index 1ab842c6032e..e25581a9f60f 100644 --- a/drivers/gpu/drm/i915/intel_ringbuffer.c +++ b/drivers/gpu/drm/i915/intel_ringbuffer.c @@ -52,20 +52,6 @@ static inline int ring_space(struct intel_ring_buffer *ring) return space; } -static u32 i915_gem_get_seqno(struct drm_device *dev) -{ - drm_i915_private_t *dev_priv = dev->dev_private; - u32 seqno; - - seqno = dev_priv->next_seqno; - - /* reserve 0 for non-seqno */ - if (++dev_priv->next_seqno == 0) - dev_priv->next_seqno = 1; - - return seqno; -} - static int render_ring_flush(struct intel_ring_buffer *ring, u32 invalidate_domains, @@ -301,7 +287,7 @@ static int init_ring_common(struct intel_ring_buffer *ring) I915_WRITE_CTL(ring, ((ring->size - PAGE_SIZE) & RING_NR_PAGES) - | RING_REPORT_64K | RING_VALID); + | RING_VALID); /* If the head is still not zero, the ring is dead */ if ((I915_READ_CTL(ring) & RING_VALID) == 0 || @@ -399,8 +385,6 @@ static int init_render_ring(struct intel_ring_buffer *ring) if (INTEL_INFO(dev)->gen > 3) { int mode = VS_TIMER_DISPATCH << 16 | VS_TIMER_DISPATCH; - if (IS_GEN6(dev) || IS_GEN7(dev)) - mode |= MI_FLUSH_ENABLE << 16 | MI_FLUSH_ENABLE; I915_WRITE(MI_MODE, mode); if (IS_GEN7(dev)) I915_WRITE(GFX_MODE_GEN7, @@ -467,7 +451,7 @@ gen6_add_request(struct intel_ring_buffer *ring, mbox1_reg = ring->signal_mbox[0]; mbox2_reg = ring->signal_mbox[1]; - *seqno = i915_gem_get_seqno(ring->dev); + *seqno = i915_gem_next_request_seqno(ring); update_mboxes(ring, *seqno, mbox1_reg); update_mboxes(ring, *seqno, mbox2_reg); @@ -565,8 +549,7 @@ static int pc_render_add_request(struct intel_ring_buffer *ring, u32 *result) { - struct drm_device *dev = ring->dev; - u32 seqno = i915_gem_get_seqno(dev); + u32 seqno = i915_gem_next_request_seqno(ring); struct pipe_control *pc = ring->private; u32 scratch_addr = pc->gtt_offset + 128; int ret; @@ -600,6 +583,7 @@ pc_render_add_request(struct intel_ring_buffer *ring, PIPE_CONTROL_FLUSH(ring, scratch_addr); scratch_addr += 128; PIPE_CONTROL_FLUSH(ring, scratch_addr); + intel_ring_emit(ring, GFX_OP_PIPE_CONTROL(4) | PIPE_CONTROL_QW_WRITE | PIPE_CONTROL_WRITE_FLUSH | PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | @@ -617,8 +601,7 @@ static int render_ring_add_request(struct intel_ring_buffer *ring, u32 *result) { - struct drm_device *dev = ring->dev; - u32 seqno = i915_gem_get_seqno(dev); + u32 seqno = i915_gem_next_request_seqno(ring); int ret; ret = intel_ring_begin(ring, 4); @@ -643,7 +626,7 @@ gen6_ring_get_seqno(struct intel_ring_buffer *ring) /* Workaround to force correct ordering between irq and seqno writes on * ivb (and maybe also on snb) by reading from a CS register (like * ACTHD) before reading the status page. */ - if (IS_GEN7(dev)) + if (IS_GEN6(dev) || IS_GEN7(dev)) intel_ring_get_active_head(ring); return intel_read_status_page(ring, I915_GEM_HWS_INDEX); } @@ -744,13 +727,13 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring) */ if (IS_GEN7(dev)) { switch (ring->id) { - case RING_RENDER: + case RCS: mmio = RENDER_HWS_PGA_GEN7; break; - case RING_BLT: + case BCS: mmio = BLT_HWS_PGA_GEN7; break; - case RING_BSD: + case VCS: mmio = BSD_HWS_PGA_GEN7; break; } @@ -792,7 +775,7 @@ ring_add_request(struct intel_ring_buffer *ring, if (ret) return ret; - seqno = i915_gem_get_seqno(ring->dev); + seqno = i915_gem_next_request_seqno(ring); intel_ring_emit(ring, MI_STORE_DWORD_INDEX); intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT); @@ -816,8 +799,7 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag) /* It looks like we need to prevent the gt from suspending while waiting * for an notifiy irq, otherwise irqs seem to get lost on at least the * blt/bsd rings on ivb. */ - if (IS_GEN7(dev)) - gen6_gt_force_wake_get(dev_priv); + gen6_gt_force_wake_get(dev_priv); spin_lock(&ring->irq_lock); if (ring->irq_refcount++ == 0) { @@ -844,8 +826,7 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag) } spin_unlock(&ring->irq_lock); - if (IS_GEN7(dev)) - gen6_gt_force_wake_put(dev_priv); + gen6_gt_force_wake_put(dev_priv); } static bool @@ -1127,24 +1108,94 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring) return 0; } -int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) +static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno) { - struct drm_device *dev = ring->dev; - struct drm_i915_private *dev_priv = dev->dev_private; - unsigned long end; - u32 head; + struct drm_i915_private *dev_priv = ring->dev->dev_private; + bool was_interruptible; + int ret; - /* If the reported head position has wrapped or hasn't advanced, - * fallback to the slow and accurate path. + /* XXX As we have not yet audited all the paths to check that + * they are ready for ERESTARTSYS from intel_ring_begin, do not + * allow us to be interruptible by a signal. */ - head = intel_read_status_page(ring, 4); - if (head > ring->head) { - ring->head = head; + was_interruptible = dev_priv->mm.interruptible; + dev_priv->mm.interruptible = false; + + ret = i915_wait_request(ring, seqno, true); + + dev_priv->mm.interruptible = was_interruptible; + + return ret; +} + +static int intel_ring_wait_request(struct intel_ring_buffer *ring, int n) +{ + struct drm_i915_gem_request *request; + u32 seqno = 0; + int ret; + + i915_gem_retire_requests_ring(ring); + + if (ring->last_retired_head != -1) { + ring->head = ring->last_retired_head; + ring->last_retired_head = -1; ring->space = ring_space(ring); if (ring->space >= n) return 0; } + list_for_each_entry(request, &ring->request_list, list) { + int space; + + if (request->tail == -1) + continue; + + space = request->tail - (ring->tail + 8); + if (space < 0) + space += ring->size; + if (space >= n) { + seqno = request->seqno; + break; + } + + /* Consume this request in case we need more space than + * is available and so need to prevent a race between + * updating last_retired_head and direct reads of + * I915_RING_HEAD. It also provides a nice sanity check. + */ + request->tail = -1; + } + + if (seqno == 0) + return -ENOSPC; + + ret = intel_ring_wait_seqno(ring, seqno); + if (ret) + return ret; + + if (WARN_ON(ring->last_retired_head == -1)) + return -ENOSPC; + + ring->head = ring->last_retired_head; + ring->last_retired_head = -1; + ring->space = ring_space(ring); + if (WARN_ON(ring->space < n)) + return -ENOSPC; + + return 0; +} + +int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n) +{ + struct drm_device *dev = ring->dev; + struct drm_i915_private *dev_priv = dev->dev_private; + unsigned long end; + int ret; + + ret = intel_ring_wait_request(ring, n); + if (ret != -ENOSPC) + return ret; + trace_i915_ring_wait_begin(ring); if (drm_core_check_feature(dev, DRIVER_GEM)) /* With GEM the hangcheck timer should kick us out of the loop, @@ -1212,7 +1263,7 @@ void intel_ring_advance(struct intel_ring_buffer *ring) static const struct intel_ring_buffer render_ring = { .name = "render ring", - .id = RING_RENDER, + .id = RCS, .mmio_base = RENDER_RING_BASE, .size = 32 * PAGE_SIZE, .init = init_render_ring, @@ -1235,7 +1286,7 @@ static const struct intel_ring_buffer render_ring = { static const struct intel_ring_buffer bsd_ring = { .name = "bsd ring", - .id = RING_BSD, + .id = VCS, .mmio_base = BSD_RING_BASE, .size = 32 * PAGE_SIZE, .init = init_ring_common, @@ -1345,7 +1396,7 @@ gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring) /* ring buffer for Video Codec for Gen6+ */ static const struct intel_ring_buffer gen6_bsd_ring = { .name = "gen6 bsd ring", - .id = RING_BSD, + .id = VCS, .mmio_base = GEN6_BSD_RING_BASE, .size = 32 * PAGE_SIZE, .init = init_ring_common, @@ -1381,79 +1432,13 @@ blt_ring_put_irq(struct intel_ring_buffer *ring) GEN6_BLITTER_USER_INTERRUPT); } - -/* 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 - */ -#define NEED_BLT_WORKAROUND(dev) \ - (IS_GEN6(dev) && (dev->pdev->revision < 8)) - -static inline struct drm_i915_gem_object * -to_blt_workaround(struct intel_ring_buffer *ring) -{ - return ring->private; -} - -static int blt_ring_init(struct intel_ring_buffer *ring) -{ - if (NEED_BLT_WORKAROUND(ring->dev)) { - struct drm_i915_gem_object *obj; - u32 *ptr; - int ret; - - obj = i915_gem_alloc_object(ring->dev, 4096); - if (obj == NULL) - return -ENOMEM; - - ret = i915_gem_object_pin(obj, 4096, true); - if (ret) { - drm_gem_object_unreference(&obj->base); - return ret; - } - - ptr = kmap(obj->pages[0]); - *ptr++ = MI_BATCH_BUFFER_END; - *ptr++ = MI_NOOP; - kunmap(obj->pages[0]); - - ret = i915_gem_object_set_to_gtt_domain(obj, false); - if (ret) { - i915_gem_object_unpin(obj); - drm_gem_object_unreference(&obj->base); - return ret; - } - - ring->private = obj; - } - - return init_ring_common(ring); -} - -static int blt_ring_begin(struct intel_ring_buffer *ring, - int num_dwords) -{ - if (ring->private) { - int ret = intel_ring_begin(ring, num_dwords+2); - if (ret) - return ret; - - intel_ring_emit(ring, MI_BATCH_BUFFER_START); - intel_ring_emit(ring, to_blt_workaround(ring)->gtt_offset); - - return 0; - } else - return intel_ring_begin(ring, 4); -} - static int blt_ring_flush(struct intel_ring_buffer *ring, u32 invalidate, u32 flush) { uint32_t cmd; int ret; - ret = blt_ring_begin(ring, 4); + ret = intel_ring_begin(ring, 4); if (ret) return ret; @@ -1468,22 +1453,12 @@ static int blt_ring_flush(struct intel_ring_buffer *ring, return 0; } -static void blt_ring_cleanup(struct intel_ring_buffer *ring) -{ - if (!ring->private) - return; - - i915_gem_object_unpin(ring->private); - drm_gem_object_unreference(ring->private); - ring->private = NULL; -} - static const struct intel_ring_buffer gen6_blt_ring = { .name = "blt ring", - .id = RING_BLT, + .id = BCS, .mmio_base = BLT_RING_BASE, .size = 32 * PAGE_SIZE, - .init = blt_ring_init, + .init = init_ring_common, .write_tail = ring_write_tail, .flush = blt_ring_flush, .add_request = gen6_add_request, @@ -1491,7 +1466,6 @@ static const struct intel_ring_buffer gen6_blt_ring = { .irq_get = blt_ring_get_irq, .irq_put = blt_ring_put_irq, .dispatch_execbuffer = gen6_ring_dispatch_execbuffer, - .cleanup = blt_ring_cleanup, .sync_to = gen6_blt_ring_sync_to, .semaphore_register = {MI_SEMAPHORE_SYNC_BR, MI_SEMAPHORE_SYNC_BV, |