summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/i915/intel_ringbuffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/i915/intel_ringbuffer.c')
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c236
1 files changed, 187 insertions, 49 deletions
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index 1d5d613eb6b..e51ab552046 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -280,6 +280,27 @@ gen7_render_ring_cs_stall_wa(struct intel_ring_buffer *ring)
return 0;
}
+static int gen7_ring_fbc_flush(struct intel_ring_buffer *ring, u32 value)
+{
+ int ret;
+
+ if (!ring->fbc_dirty)
+ return 0;
+
+ ret = intel_ring_begin(ring, 4);
+ if (ret)
+ return ret;
+ intel_ring_emit(ring, MI_NOOP);
+ /* WaFbcNukeOn3DBlt:ivb/hsw */
+ intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
+ intel_ring_emit(ring, MSG_FBC_REND_STATE);
+ intel_ring_emit(ring, value);
+ intel_ring_advance(ring);
+
+ ring->fbc_dirty = false;
+ return 0;
+}
+
static int
gen7_render_ring_flush(struct intel_ring_buffer *ring,
u32 invalidate_domains, u32 flush_domains)
@@ -336,6 +357,9 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring,
intel_ring_emit(ring, 0);
intel_ring_advance(ring);
+ if (flush_domains)
+ return gen7_ring_fbc_flush(ring, FBC_REND_NUKE);
+
return 0;
}
@@ -429,6 +453,8 @@ static int init_ring_common(struct intel_ring_buffer *ring)
ring->last_retired_head = -1;
}
+ memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
+
out:
if (HAS_FORCE_WAKE(dev))
gen6_gt_force_wake_put(dev_priv);
@@ -464,9 +490,11 @@ init_pipe_control(struct intel_ring_buffer *ring)
goto err_unref;
pc->gtt_offset = obj->gtt_offset;
- pc->cpu_page = kmap(sg_page(obj->pages->sgl));
- if (pc->cpu_page == NULL)
+ pc->cpu_page = kmap(sg_page(obj->pages->sgl));
+ if (pc->cpu_page == NULL) {
+ ret = -ENOMEM;
goto err_unpin;
+ }
DRM_DEBUG_DRIVER("%s pipe control offset: 0x%08x\n",
ring->name, pc->gtt_offset);
@@ -515,6 +543,8 @@ static int init_render_ring(struct intel_ring_buffer *ring)
/* We need to disable the AsyncFlip performance optimisations in order
* to use MI_WAIT_FOR_EVENT within the CS. It should already be
* programmed to '1' on all products.
+ *
+ * WaDisableAsyncFlipPerfMode:snb,ivb,hsw,vlv
*/
if (INTEL_INFO(dev)->gen >= 6)
I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
@@ -556,7 +586,7 @@ static int init_render_ring(struct intel_ring_buffer *ring)
I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
if (HAS_L3_GPU_CACHE(dev))
- I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+ I915_WRITE_IMR(ring, ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
return ret;
}
@@ -578,9 +608,16 @@ static void
update_mboxes(struct intel_ring_buffer *ring,
u32 mmio_offset)
{
+/* NB: In order to be able to do semaphore MBOX updates for varying number
+ * of rings, it's easiest if we round up each individual update to a
+ * multiple of 2 (since ring updates must always be a multiple of 2)
+ * even though the actual update only requires 3 dwords.
+ */
+#define MBOX_UPDATE_DWORDS 4
intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
intel_ring_emit(ring, mmio_offset);
intel_ring_emit(ring, ring->outstanding_lazy_request);
+ intel_ring_emit(ring, MI_NOOP);
}
/**
@@ -595,19 +632,24 @@ update_mboxes(struct intel_ring_buffer *ring,
static int
gen6_add_request(struct intel_ring_buffer *ring)
{
- u32 mbox1_reg;
- u32 mbox2_reg;
- int ret;
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *useless;
+ int i, ret;
- ret = intel_ring_begin(ring, 10);
+ ret = intel_ring_begin(ring, ((I915_NUM_RINGS-1) *
+ MBOX_UPDATE_DWORDS) +
+ 4);
if (ret)
return ret;
+#undef MBOX_UPDATE_DWORDS
- mbox1_reg = ring->signal_mbox[0];
- mbox2_reg = ring->signal_mbox[1];
+ for_each_ring(useless, dev_priv, i) {
+ u32 mbox_reg = ring->signal_mbox[i];
+ if (mbox_reg != GEN6_NOSYNC)
+ update_mboxes(ring, mbox_reg);
+ }
- update_mboxes(ring, mbox1_reg);
- update_mboxes(ring, mbox2_reg);
intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
intel_ring_emit(ring, ring->outstanding_lazy_request);
@@ -779,7 +821,7 @@ gen5_ring_get_irq(struct intel_ring_buffer *ring)
return false;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (ring->irq_refcount++ == 0) {
+ if (ring->irq_refcount.gt++ == 0) {
dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
POSTING_READ(GTIMR);
@@ -797,7 +839,7 @@ gen5_ring_put_irq(struct intel_ring_buffer *ring)
unsigned long flags;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (--ring->irq_refcount == 0) {
+ if (--ring->irq_refcount.gt == 0) {
dev_priv->gt_irq_mask |= ring->irq_enable_mask;
I915_WRITE(GTIMR, dev_priv->gt_irq_mask);
POSTING_READ(GTIMR);
@@ -816,7 +858,7 @@ i9xx_ring_get_irq(struct intel_ring_buffer *ring)
return false;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (ring->irq_refcount++ == 0) {
+ if (ring->irq_refcount.gt++ == 0) {
dev_priv->irq_mask &= ~ring->irq_enable_mask;
I915_WRITE(IMR, dev_priv->irq_mask);
POSTING_READ(IMR);
@@ -834,7 +876,7 @@ i9xx_ring_put_irq(struct intel_ring_buffer *ring)
unsigned long flags;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (--ring->irq_refcount == 0) {
+ if (--ring->irq_refcount.gt == 0) {
dev_priv->irq_mask |= ring->irq_enable_mask;
I915_WRITE(IMR, dev_priv->irq_mask);
POSTING_READ(IMR);
@@ -853,7 +895,7 @@ i8xx_ring_get_irq(struct intel_ring_buffer *ring)
return false;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (ring->irq_refcount++ == 0) {
+ if (ring->irq_refcount.gt++ == 0) {
dev_priv->irq_mask &= ~ring->irq_enable_mask;
I915_WRITE16(IMR, dev_priv->irq_mask);
POSTING_READ16(IMR);
@@ -871,7 +913,7 @@ i8xx_ring_put_irq(struct intel_ring_buffer *ring)
unsigned long flags;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (--ring->irq_refcount == 0) {
+ if (--ring->irq_refcount.gt == 0) {
dev_priv->irq_mask |= ring->irq_enable_mask;
I915_WRITE16(IMR, dev_priv->irq_mask);
POSTING_READ16(IMR);
@@ -899,6 +941,9 @@ void intel_ring_setup_status_page(struct intel_ring_buffer *ring)
case VCS:
mmio = BSD_HWS_PGA_GEN7;
break;
+ case VECS:
+ mmio = VEBOX_HWS_PGA_GEN7;
+ break;
}
} else if (IS_GEN6(ring->dev)) {
mmio = RING_HWS_PGA_GEN6(ring->mmio_base);
@@ -961,10 +1006,11 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
gen6_gt_force_wake_get(dev_priv);
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (ring->irq_refcount++ == 0) {
+ if (ring->irq_refcount.gt++ == 0) {
if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
- I915_WRITE_IMR(ring, ~(ring->irq_enable_mask |
- GEN6_RENDER_L3_PARITY_ERROR));
+ I915_WRITE_IMR(ring,
+ ~(ring->irq_enable_mask |
+ GT_RENDER_L3_PARITY_ERROR_INTERRUPT));
else
I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
dev_priv->gt_irq_mask &= ~ring->irq_enable_mask;
@@ -984,9 +1030,10 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
unsigned long flags;
spin_lock_irqsave(&dev_priv->irq_lock, flags);
- if (--ring->irq_refcount == 0) {
+ if (--ring->irq_refcount.gt == 0) {
if (HAS_L3_GPU_CACHE(dev) && ring->id == RCS)
- I915_WRITE_IMR(ring, ~GEN6_RENDER_L3_PARITY_ERROR);
+ I915_WRITE_IMR(ring,
+ ~GT_RENDER_L3_PARITY_ERROR_INTERRUPT);
else
I915_WRITE_IMR(ring, ~0);
dev_priv->gt_irq_mask |= ring->irq_enable_mask;
@@ -998,6 +1045,48 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
gen6_gt_force_wake_put(dev_priv);
}
+static bool
+hsw_vebox_get_irq(struct intel_ring_buffer *ring)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ if (!dev->irq_enabled)
+ return false;
+
+ spin_lock_irqsave(&dev_priv->rps.lock, flags);
+ if (ring->irq_refcount.pm++ == 0) {
+ u32 pm_imr = I915_READ(GEN6_PMIMR);
+ I915_WRITE_IMR(ring, ~ring->irq_enable_mask);
+ I915_WRITE(GEN6_PMIMR, pm_imr & ~ring->irq_enable_mask);
+ POSTING_READ(GEN6_PMIMR);
+ }
+ spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+
+ return true;
+}
+
+static void
+hsw_vebox_put_irq(struct intel_ring_buffer *ring)
+{
+ struct drm_device *dev = ring->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ unsigned long flags;
+
+ if (!dev->irq_enabled)
+ return;
+
+ spin_lock_irqsave(&dev_priv->rps.lock, flags);
+ if (--ring->irq_refcount.pm == 0) {
+ u32 pm_imr = I915_READ(GEN6_PMIMR);
+ I915_WRITE_IMR(ring, ~0);
+ I915_WRITE(GEN6_PMIMR, pm_imr | ring->irq_enable_mask);
+ POSTING_READ(GEN6_PMIMR);
+ }
+ spin_unlock_irqrestore(&dev_priv->rps.lock, flags);
+}
+
static int
i965_dispatch_execbuffer(struct intel_ring_buffer *ring,
u32 offset, u32 length,
@@ -1423,7 +1512,7 @@ int intel_ring_idle(struct intel_ring_buffer *ring)
/* We need to add any requests required to flush the objects and ring */
if (ring->outstanding_lazy_request) {
- ret = i915_add_request(ring, NULL, NULL);
+ ret = i915_add_request(ring, NULL);
if (ret)
return ret;
}
@@ -1500,6 +1589,7 @@ void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno)
}
ring->set_seqno(ring, seqno);
+ ring->hangcheck.seqno = seqno;
}
void intel_ring_advance(struct intel_ring_buffer *ring)
@@ -1546,8 +1636,8 @@ static void gen6_bsd_ring_write_tail(struct intel_ring_buffer *ring,
_MASKED_BIT_DISABLE(GEN6_BSD_SLEEP_MSG_DISABLE));
}
-static int gen6_ring_flush(struct intel_ring_buffer *ring,
- u32 invalidate, u32 flush)
+static int gen6_bsd_ring_flush(struct intel_ring_buffer *ring,
+ u32 invalidate, u32 flush)
{
uint32_t cmd;
int ret;
@@ -1618,9 +1708,10 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
/* Blitter support (SandyBridge+) */
-static int blt_ring_flush(struct intel_ring_buffer *ring,
- u32 invalidate, u32 flush)
+static int gen6_ring_flush(struct intel_ring_buffer *ring,
+ u32 invalidate, u32 flush)
{
+ struct drm_device *dev = ring->dev;
uint32_t cmd;
int ret;
@@ -1643,6 +1734,10 @@ static int blt_ring_flush(struct intel_ring_buffer *ring,
intel_ring_emit(ring, 0);
intel_ring_emit(ring, MI_NOOP);
intel_ring_advance(ring);
+
+ if (IS_GEN7(dev) && flush)
+ return gen7_ring_fbc_flush(ring, FBC_REND_CACHE_CLEAN);
+
return 0;
}
@@ -1662,15 +1757,18 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
ring->flush = gen6_render_ring_flush;
ring->irq_get = gen6_ring_get_irq;
ring->irq_put = gen6_ring_put_irq;
- ring->irq_enable_mask = GT_USER_INTERRUPT;
+ ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT;
ring->get_seqno = gen6_ring_get_seqno;
ring->set_seqno = ring_set_seqno;
ring->sync_to = gen6_ring_sync;
- ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_INVALID;
- ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_RV;
- ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_RB;
- ring->signal_mbox[0] = GEN6_VRSYNC;
- ring->signal_mbox[1] = GEN6_BRSYNC;
+ ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_RV;
+ ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_RB;
+ ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_RVE;
+ ring->signal_mbox[RCS] = GEN6_NOSYNC;
+ ring->signal_mbox[VCS] = GEN6_VRSYNC;
+ ring->signal_mbox[BCS] = GEN6_BRSYNC;
+ ring->signal_mbox[VECS] = GEN6_VERSYNC;
} else if (IS_GEN5(dev)) {
ring->add_request = pc_render_add_request;
ring->flush = gen4_render_ring_flush;
@@ -1678,7 +1776,8 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
ring->set_seqno = pc_render_set_seqno;
ring->irq_get = gen5_ring_get_irq;
ring->irq_put = gen5_ring_put_irq;
- ring->irq_enable_mask = GT_USER_INTERRUPT | GT_PIPE_NOTIFY;
+ ring->irq_enable_mask = GT_RENDER_USER_INTERRUPT |
+ GT_RENDER_PIPECTL_NOTIFY_INTERRUPT;
} else {
ring->add_request = i9xx_add_request;
if (INTEL_INFO(dev)->gen < 4)
@@ -1816,20 +1915,23 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
/* gen6 bsd needs a special wa for tail updates */
if (IS_GEN6(dev))
ring->write_tail = gen6_bsd_ring_write_tail;
- ring->flush = gen6_ring_flush;
+ ring->flush = gen6_bsd_ring_flush;
ring->add_request = gen6_add_request;
ring->get_seqno = gen6_ring_get_seqno;
ring->set_seqno = ring_set_seqno;
- ring->irq_enable_mask = GEN6_BSD_USER_INTERRUPT;
+ ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
ring->irq_get = gen6_ring_get_irq;
ring->irq_put = gen6_ring_put_irq;
ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
ring->sync_to = gen6_ring_sync;
- ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_VR;
- ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_INVALID;
- ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_VB;
- ring->signal_mbox[0] = GEN6_RVSYNC;
- ring->signal_mbox[1] = GEN6_BVSYNC;
+ ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VR;
+ ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VB;
+ ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_VVE;
+ ring->signal_mbox[RCS] = GEN6_RVSYNC;
+ ring->signal_mbox[VCS] = GEN6_NOSYNC;
+ ring->signal_mbox[BCS] = GEN6_BVSYNC;
+ ring->signal_mbox[VECS] = GEN6_VEVSYNC;
} else {
ring->mmio_base = BSD_RING_BASE;
ring->flush = bsd_ring_flush;
@@ -1837,7 +1939,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
ring->get_seqno = ring_get_seqno;
ring->set_seqno = ring_set_seqno;
if (IS_GEN5(dev)) {
- ring->irq_enable_mask = GT_BSD_USER_INTERRUPT;
+ ring->irq_enable_mask = ILK_BSD_USER_INTERRUPT;
ring->irq_get = gen5_ring_get_irq;
ring->irq_put = gen5_ring_put_irq;
} else {
@@ -1862,20 +1964,56 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
ring->mmio_base = BLT_RING_BASE;
ring->write_tail = ring_write_tail;
- ring->flush = blt_ring_flush;
+ ring->flush = gen6_ring_flush;
ring->add_request = gen6_add_request;
ring->get_seqno = gen6_ring_get_seqno;
ring->set_seqno = ring_set_seqno;
- ring->irq_enable_mask = GEN6_BLITTER_USER_INTERRUPT;
+ ring->irq_enable_mask = GT_BLT_USER_INTERRUPT;
ring->irq_get = gen6_ring_get_irq;
ring->irq_put = gen6_ring_put_irq;
ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
ring->sync_to = gen6_ring_sync;
- ring->semaphore_register[0] = MI_SEMAPHORE_SYNC_BR;
- ring->semaphore_register[1] = MI_SEMAPHORE_SYNC_BV;
- ring->semaphore_register[2] = MI_SEMAPHORE_SYNC_INVALID;
- ring->signal_mbox[0] = GEN6_RBSYNC;
- ring->signal_mbox[1] = GEN6_VBSYNC;
+ ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_BR;
+ ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_BV;
+ ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_BVE;
+ ring->signal_mbox[RCS] = GEN6_RBSYNC;
+ ring->signal_mbox[VCS] = GEN6_VBSYNC;
+ ring->signal_mbox[BCS] = GEN6_NOSYNC;
+ ring->signal_mbox[VECS] = GEN6_VEBSYNC;
+ ring->init = init_ring_common;
+
+ return intel_init_ring_buffer(dev, ring);
+}
+
+int intel_init_vebox_ring_buffer(struct drm_device *dev)
+{
+ drm_i915_private_t *dev_priv = dev->dev_private;
+ struct intel_ring_buffer *ring = &dev_priv->ring[VECS];
+
+ ring->name = "video enhancement ring";
+ ring->id = VECS;
+
+ ring->mmio_base = VEBOX_RING_BASE;
+ ring->write_tail = ring_write_tail;
+ ring->flush = gen6_ring_flush;
+ ring->add_request = gen6_add_request;
+ ring->get_seqno = gen6_ring_get_seqno;
+ ring->set_seqno = ring_set_seqno;
+ ring->irq_enable_mask = PM_VEBOX_USER_INTERRUPT |
+ PM_VEBOX_CS_ERROR_INTERRUPT;
+ ring->irq_get = hsw_vebox_get_irq;
+ ring->irq_put = hsw_vebox_put_irq;
+ ring->dispatch_execbuffer = gen6_ring_dispatch_execbuffer;
+ ring->sync_to = gen6_ring_sync;
+ ring->semaphore_register[RCS] = MI_SEMAPHORE_SYNC_VER;
+ ring->semaphore_register[VCS] = MI_SEMAPHORE_SYNC_VEV;
+ ring->semaphore_register[BCS] = MI_SEMAPHORE_SYNC_VEB;
+ ring->semaphore_register[VECS] = MI_SEMAPHORE_SYNC_INVALID;
+ ring->signal_mbox[RCS] = GEN6_RVESYNC;
+ ring->signal_mbox[VCS] = GEN6_VVESYNC;
+ ring->signal_mbox[BCS] = GEN6_BVESYNC;
+ ring->signal_mbox[VECS] = GEN6_NOSYNC;
ring->init = init_ring_common;
return intel_init_ring_buffer(dev, ring);