drm/i915: export error state ref handling
[deliverable/linux.git] / drivers / gpu / drm / i915 / intel_ringbuffer.c
index 1d5d613eb6be4d21affe491af19a3eaba99325ee..e51ab552046c9ef943ec7d7bb1de5b5e24467154 100644 (file)
@@ -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);
This page took 0.029976 seconds and 5 git commands to generate.