drm/i915: open code gen6+ ring irqs
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / i915 / intel_ringbuffer.c
index 77e729d4e4f02476b289aed344d344411c0eb2c1..98ac5c0ca37ae14dab0ce96bcf72821d60f5e1c9 100644 (file)
@@ -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,
@@ -304,9 +290,9 @@ static int init_ring_common(struct intel_ring_buffer *ring)
                        | RING_REPORT_64K | RING_VALID);
 
        /* If the head is still not zero, the ring is dead */
-       if ((I915_READ_CTL(ring) & RING_VALID) == 0 ||
-           I915_READ_START(ring) != obj->gtt_offset ||
-           (I915_READ_HEAD(ring) & HEAD_ADDR) != 0) {
+       if (wait_for((I915_READ_CTL(ring) & RING_VALID) != 0 &&
+                    I915_READ_START(ring) == obj->gtt_offset &&
+                    (I915_READ_HEAD(ring) & HEAD_ADDR) == 0, 50)) {
                DRM_ERROR("%s initialization failed "
                                "ctl %08x head %08x tail %08x start %08x\n",
                                ring->name,
@@ -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);
@@ -635,6 +618,19 @@ render_ring_add_request(struct intel_ring_buffer *ring,
        return 0;
 }
 
+static u32
+gen6_ring_get_seqno(struct intel_ring_buffer *ring)
+{
+       struct drm_device *dev = ring->dev;
+
+       /* 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))
+               intel_ring_get_active_head(ring);
+       return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
 static u32
 ring_get_seqno(struct intel_ring_buffer *ring)
 {
@@ -691,7 +687,7 @@ render_ring_get_irq(struct intel_ring_buffer *ring)
 
        spin_lock(&ring->irq_lock);
        if (ring->irq_refcount++ == 0) {
-               if (HAS_PCH_SPLIT(dev))
+               if (HAS_PCH_SPLIT(dev) || IS_VALLEYVIEW(dev))
                        ironlake_enable_irq(dev_priv,
                                            GT_PIPE_NOTIFY | GT_USER_INTERRUPT);
                else
@@ -710,7 +706,7 @@ render_ring_put_irq(struct intel_ring_buffer *ring)
 
        spin_lock(&ring->irq_lock);
        if (--ring->irq_refcount == 0) {
-               if (HAS_PCH_SPLIT(dev))
+               if (HAS_PCH_SPLIT(dev) || IS_VALLEYVIEW(dev))
                        ironlake_disable_irq(dev_priv,
                                             GT_USER_INTERRUPT |
                                             GT_PIPE_NOTIFY);
@@ -731,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;
                }
@@ -779,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);
@@ -792,30 +788,25 @@ ring_add_request(struct intel_ring_buffer *ring,
 }
 
 static bool
-gen7_blt_ring_get_irq(struct intel_ring_buffer *ring)
-{
-       /* The BLT ring on IVB appears to have broken synchronization
-        * between the seqno write and the interrupt, so that the
-        * interrupt appears first.  Returning false here makes
-        * i915_wait_request() do a polling loop, instead.
-        */
-       return false;
-}
-
-static bool
-gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+gen6_ring_get_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       u32 mask = ring->irq_enable;
 
        if (!dev->irq_enabled)
               return false;
 
+       /* 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. */
+       gen6_gt_force_wake_get(dev_priv);
+
        spin_lock(&ring->irq_lock);
        if (ring->irq_refcount++ == 0) {
-               ring->irq_mask &= ~rflag;
+               ring->irq_mask &= ~mask;
                I915_WRITE_IMR(ring, ring->irq_mask);
-               ironlake_enable_irq(dev_priv, gflag);
+               ironlake_enable_irq(dev_priv, mask);
        }
        spin_unlock(&ring->irq_lock);
 
@@ -823,18 +814,21 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
 }
 
 static void
-gen6_ring_put_irq(struct intel_ring_buffer *ring, u32 gflag, u32 rflag)
+gen6_ring_put_irq(struct intel_ring_buffer *ring)
 {
        struct drm_device *dev = ring->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
+       u32 mask = ring->irq_enable;
 
        spin_lock(&ring->irq_lock);
        if (--ring->irq_refcount == 0) {
-               ring->irq_mask |= rflag;
+               ring->irq_mask |= mask;
                I915_WRITE_IMR(ring, ring->irq_mask);
-               ironlake_disable_irq(dev_priv, gflag);
+               ironlake_disable_irq(dev_priv, mask);
        }
        spin_unlock(&ring->irq_lock);
+
+       gen6_gt_force_wake_put(dev_priv);
 }
 
 static bool
@@ -1116,11 +1110,89 @@ static int intel_wrap_ring_buffer(struct intel_ring_buffer *ring)
        return 0;
 }
 
+static int intel_ring_wait_seqno(struct intel_ring_buffer *ring, u32 seqno)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       bool was_interruptible;
+       int ret;
+
+       /* 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.
+        */
+       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;
        u32 head;
 
        /* If the reported head position has wrapped or hasn't advanced,
@@ -1134,6 +1206,10 @@ int intel_wait_ring_buffer(struct intel_ring_buffer *ring, int n)
                        return 0;
        }
 
+       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,
@@ -1201,7 +1277,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,
@@ -1224,7 +1300,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,
@@ -1299,51 +1375,20 @@ gen6_ring_dispatch_execbuffer(struct intel_ring_buffer *ring,
        return 0;
 }
 
-static bool
-gen6_render_ring_get_irq(struct intel_ring_buffer *ring)
-{
-       return gen6_ring_get_irq(ring,
-                                GT_USER_INTERRUPT,
-                                GEN6_RENDER_USER_INTERRUPT);
-}
-
-static void
-gen6_render_ring_put_irq(struct intel_ring_buffer *ring)
-{
-       return gen6_ring_put_irq(ring,
-                                GT_USER_INTERRUPT,
-                                GEN6_RENDER_USER_INTERRUPT);
-}
-
-static bool
-gen6_bsd_ring_get_irq(struct intel_ring_buffer *ring)
-{
-       return gen6_ring_get_irq(ring,
-                                GT_GEN6_BSD_USER_INTERRUPT,
-                                GEN6_BSD_USER_INTERRUPT);
-}
-
-static void
-gen6_bsd_ring_put_irq(struct intel_ring_buffer *ring)
-{
-       return gen6_ring_put_irq(ring,
-                                GT_GEN6_BSD_USER_INTERRUPT,
-                                GEN6_BSD_USER_INTERRUPT);
-}
-
 /* 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,
        .write_tail             = gen6_bsd_ring_write_tail,
        .flush                  = gen6_ring_flush,
        .add_request            = gen6_add_request,
-       .get_seqno              = ring_get_seqno,
-       .irq_get                = gen6_bsd_ring_get_irq,
-       .irq_put                = gen6_bsd_ring_put_irq,
+       .get_seqno              = gen6_ring_get_seqno,
+       .irq_enable             = GEN6_BSD_USER_INTERRUPT,
+       .irq_get                = gen6_ring_get_irq,
+       .irq_put                = gen6_ring_put_irq,
        .dispatch_execbuffer    = gen6_ring_dispatch_execbuffer,
        .sync_to                = gen6_bsd_ring_sync_to,
        .semaphore_register     = {MI_SEMAPHORE_SYNC_VR,
@@ -1354,95 +1399,13 @@ static const struct intel_ring_buffer gen6_bsd_ring = {
 
 /* Blitter support (SandyBridge+) */
 
-static bool
-blt_ring_get_irq(struct intel_ring_buffer *ring)
-{
-       return gen6_ring_get_irq(ring,
-                                GT_BLT_USER_INTERRUPT,
-                                GEN6_BLITTER_USER_INTERRUPT);
-}
-
-static void
-blt_ring_put_irq(struct intel_ring_buffer *ring)
-{
-       gen6_ring_put_irq(ring,
-                         GT_BLT_USER_INTERRUPT,
-                         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;
 
@@ -1457,30 +1420,20 @@ 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,
-       .get_seqno              = ring_get_seqno,
-       .irq_get                = blt_ring_get_irq,
-       .irq_put                = blt_ring_put_irq,
+       .get_seqno              = gen6_ring_get_seqno,
+       .irq_get                = gen6_ring_get_irq,
+       .irq_put                = gen6_ring_put_irq,
+       .irq_enable             = GEN6_BLITTER_USER_INTERRUPT,
        .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,
@@ -1497,8 +1450,10 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
        if (INTEL_INFO(dev)->gen >= 6) {
                ring->add_request = gen6_add_request;
                ring->flush = gen6_render_ring_flush;
-               ring->irq_get = gen6_render_ring_get_irq;
-               ring->irq_put = gen6_render_ring_put_irq;
+               ring->irq_get = gen6_ring_get_irq;
+               ring->irq_put = gen6_ring_put_irq;
+               ring->irq_enable = GT_USER_INTERRUPT;
+               ring->get_seqno = gen6_ring_get_seqno;
        } else if (IS_GEN5(dev)) {
                ring->add_request = pc_render_add_request;
                ring->get_seqno = pc_render_get_seqno;
@@ -1520,8 +1475,9 @@ int intel_render_ring_init_dri(struct drm_device *dev, u64 start, u32 size)
        *ring = render_ring;
        if (INTEL_INFO(dev)->gen >= 6) {
                ring->add_request = gen6_add_request;
-               ring->irq_get = gen6_render_ring_get_irq;
-               ring->irq_put = gen6_render_ring_put_irq;
+               ring->irq_get = gen6_ring_get_irq;
+               ring->irq_put = gen6_ring_put_irq;
+               ring->irq_enable = GT_USER_INTERRUPT;
        } else if (IS_GEN5(dev)) {
                ring->add_request = pc_render_add_request;
                ring->get_seqno = pc_render_get_seqno;
@@ -1577,8 +1533,5 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
 
        *ring = gen6_blt_ring;
 
-       if (IS_GEN7(dev))
-               ring->irq_get = gen7_blt_ring_get_irq;
-
        return intel_init_ring_buffer(dev, ring);
 }