]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'drm-intel-next-2014-09-01' of git://anongit.freedesktop.org/drm-intel...
authorDave Airlie <airlied@redhat.com>
Tue, 2 Sep 2014 22:30:48 +0000 (08:30 +1000)
committerDave Airlie <airlied@redhat.com>
Tue, 2 Sep 2014 22:30:48 +0000 (08:30 +1000)
drm-intel-next-2014-08-22:
- basic code for execlist, which is the fancy new cmd submission on gen8. Still
  disabled by default (Ben, Oscar Mateo, Thomas Daniel et al)
- remove the useless usage of console_lock for I915_FBDEV=n (Chris)
- clean up relations between ctx and ppgtt
- clean up ppgtt lifetime handling (Michel Thierry)
- various cursor code improvements from Ville
- execbuffer code cleanups and secure batch fixes (Chris)
- prep work for dev -> dev_priv transition (Chris)
- some of the prep patches for the seqno -> request object transition (Chris)
- various small improvements all over

* tag 'drm-intel-next-2014-09-01' of git://anongit.freedesktop.org/drm-intel: (86 commits)
  drm/i915: fix suspend/resume for GENs w/o runtime PM support
  drm/i915: Update DRIVER_DATE to 20140822
  drm: fix plane rotation when restoring fbdev configuration
  drm/i915/bdw: Disable execlists by default
  drm/i915/bdw: Enable Logical Ring Contexts (hence, Execlists)
  drm/i915/bdw: Document Logical Rings, LR contexts and Execlists
  drm/i915/bdw: Print context state in debugfs
  drm/i915/bdw: Display context backing obj & ringbuffer info in debugfs
  drm/i915/bdw: Display execlists info in debugfs
  drm/i915/bdw: Disable semaphores for Execlists
  drm/i915/bdw: Make sure gpu reset still works with Execlists
  drm/i915/bdw: Don't write PDP in the legacy way when using LRCs
  drm/i915: Track cursor changes as frontbuffer tracking flushes
  drm/i915/bdw: Help out the ctx switch interrupt handler
  drm/i915/bdw: Avoid non-lite-restore preemptions
  drm/i915/bdw: Handle context switch events
  drm/i915/bdw: Two-stage execlist submit process
  drm/i915/bdw: Write the tail pointer, LRC style
  drm/i915/bdw: Implement context switching (somewhat)
  drm/i915/bdw: Emission of requests with logical rings
  ...

Conflicts:
drivers/gpu/drm/i915/i915_drv.c

30 files changed:
Documentation/DocBook/drm.tmpl
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/i915_cmd_parser.c
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_gem_execbuffer.c
drivers/gpu/drm/i915/i915_gem_gtt.c
drivers/gpu/drm/i915/i915_gem_gtt.h
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_params.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/intel_ddi.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_dp.c
drivers/gpu/drm/i915/intel_drv.h
drivers/gpu/drm/i915/intel_fbdev.c
drivers/gpu/drm/i915/intel_lrc.c [new file with mode: 0644]
drivers/gpu/drm/i915/intel_lrc.h [new file with mode: 0644]
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_ringbuffer.h
include/drm/drm_crtc.h

index 5c299fa4e01676a00025d8492903bbce12cb0275..58ab4d32c86fe0b30a99f30ce3f37d4d2646f3d9 100644 (file)
@@ -3919,6 +3919,11 @@ int num_ioctls;</synopsis>
 !Pdrivers/gpu/drm/i915/i915_cmd_parser.c batch buffer command parser
 !Idrivers/gpu/drm/i915/i915_cmd_parser.c
       </sect2>
+      <sect2>
+        <title>Logical Rings, Logical Ring Contexts and Execlists</title>
+!Pdrivers/gpu/drm/i915/intel_lrc.c Logical Rings, Logical Ring Contexts and Execlists
+!Idrivers/gpu/drm/i915/intel_lrc.c
+      </sect2>
     </sect1>
   </chapter>
 </part>
index f09b75212081ae7256e00d9845c31eabc3dfc2c5..7d7c1fd15443f233cc8c75f4dd729abe32c4ff8b 100644 (file)
@@ -4175,12 +4175,25 @@ static int drm_mode_crtc_set_obj_prop(struct drm_mode_object *obj,
        return ret;
 }
 
-static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
-                                     struct drm_property *property,
-                                     uint64_t value)
+/**
+ * drm_mode_plane_set_obj_prop - set the value of a property
+ * @plane: drm plane object to set property value for
+ * @property: property to set
+ * @value: value the property should be set to
+ *
+ * This functions sets a given property on a given plane object. This function
+ * calls the driver's ->set_property callback and changes the software state of
+ * the property if the callback succeeds.
+ *
+ * Returns:
+ * Zero on success, error code on failure.
+ */
+int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+                               struct drm_property *property,
+                               uint64_t value)
 {
        int ret = -EINVAL;
-       struct drm_plane *plane = obj_to_plane(obj);
+       struct drm_mode_object *obj = &plane->base;
 
        if (plane->funcs->set_property)
                ret = plane->funcs->set_property(plane, property, value);
@@ -4189,6 +4202,7 @@ static int drm_mode_plane_set_obj_prop(struct drm_mode_object *obj,
 
        return ret;
 }
+EXPORT_SYMBOL(drm_mode_plane_set_obj_prop);
 
 /**
  * drm_mode_getproperty_ioctl - get the current value of a object's property
@@ -4327,7 +4341,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
                ret = drm_mode_crtc_set_obj_prop(arg_obj, property, arg->value);
                break;
        case DRM_MODE_OBJECT_PLANE:
-               ret = drm_mode_plane_set_obj_prop(arg_obj, property, arg->value);
+               ret = drm_mode_plane_set_obj_prop(obj_to_plane(arg_obj),
+                                                 property, arg->value);
                break;
        }
 
index 63d7b8eb6c1746654c36005f5674d51fcd50306c..0c0c39bac23da21a368ef94681da10b173994660 100644 (file)
@@ -296,9 +296,9 @@ static bool restore_fbdev_mode(struct drm_fb_helper *fb_helper)
                        drm_plane_force_disable(plane);
 
                if (dev->mode_config.rotation_property) {
-                       drm_object_property_set_value(&plane->base,
-                                       dev->mode_config.rotation_property,
-                                       BIT(DRM_ROTATE_0));
+                       drm_mode_plane_set_obj_prop(plane,
+                                                   dev->mode_config.rotation_property,
+                                                   BIT(DRM_ROTATE_0));
                }
        }
 
index 91bd167e1cb70322998d92050d01f43eae7d0888..c1dd485aeb6c255230c83e7fea876fb79fed3308 100644 (file)
@@ -31,6 +31,7 @@ i915-y += i915_cmd_parser.o \
          i915_gpu_error.o \
          i915_irq.o \
          i915_trace_points.o \
+         intel_lrc.o \
          intel_ringbuffer.o \
          intel_uncore.o
 
index dea99d92fb4a195784c288f3fbc236c00a8188c2..c45856bcc8b910c568f611c011ee9df91e423326 100644 (file)
@@ -842,8 +842,6 @@ finish:
  */
 bool i915_needs_cmd_parser(struct intel_engine_cs *ring)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
-
        if (!ring->needs_cmd_parser)
                return false;
 
@@ -852,7 +850,7 @@ bool i915_needs_cmd_parser(struct intel_engine_cs *ring)
         * disabled. That will cause all of the parser's PPGTT checks to
         * fail. For now, disable parsing when PPGTT is off.
         */
-       if (!dev_priv->mm.aliasing_ppgtt)
+       if (USES_PPGTT(ring->dev))
                return false;
 
        return (i915.enable_cmd_parser == 1);
index 330caa1ab9f92120777f388df3a4d402066e3eca..6c82bdaa0822699f221174dcc3e6a50556918632 100644 (file)
@@ -333,7 +333,7 @@ static int per_file_stats(int id, void *ptr, void *data)
                        }
 
                        ppgtt = container_of(vma->vm, struct i915_hw_ppgtt, base);
-                       if (ppgtt->ctx && ppgtt->ctx->file_priv != stats->file_priv)
+                       if (ppgtt->file_priv != stats->file_priv)
                                continue;
 
                        if (obj->ring) /* XXX per-vma statistic */
@@ -703,6 +703,12 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                }
 
                for_each_pipe(pipe) {
+                       if (!intel_display_power_enabled(dev_priv,
+                                               POWER_DOMAIN_PIPE(pipe))) {
+                               seq_printf(m, "Pipe %c power disabled\n",
+                                          pipe_name(pipe));
+                               continue;
+                       }
                        seq_printf(m, "Pipe %c IMR:\t%08x\n",
                                   pipe_name(pipe),
                                   I915_READ(GEN8_DE_PIPE_IMR(pipe)));
@@ -1671,6 +1677,14 @@ static int i915_gem_framebuffer_info(struct seq_file *m, void *data)
        return 0;
 }
 
+static void describe_ctx_ringbuf(struct seq_file *m,
+                                struct intel_ringbuffer *ringbuf)
+{
+       seq_printf(m, " (ringbuffer, space: %d, head: %u, tail: %u, last head: %d)",
+                  ringbuf->space, ringbuf->head, ringbuf->tail,
+                  ringbuf->last_retired_head);
+}
+
 static int i915_context_status(struct seq_file *m, void *unused)
 {
        struct drm_info_node *node = m->private;
@@ -1697,16 +1711,168 @@ static int i915_context_status(struct seq_file *m, void *unused)
        }
 
        list_for_each_entry(ctx, &dev_priv->context_list, link) {
-               if (ctx->legacy_hw_ctx.rcs_state == NULL)
+               if (!i915.enable_execlists &&
+                   ctx->legacy_hw_ctx.rcs_state == NULL)
                        continue;
 
                seq_puts(m, "HW context ");
                describe_ctx(m, ctx);
-               for_each_ring(ring, dev_priv, i)
+               for_each_ring(ring, dev_priv, i) {
+                       if (ring->default_context == ctx)
+                               seq_printf(m, "(default context %s) ",
+                                          ring->name);
+               }
+
+               if (i915.enable_execlists) {
+                       seq_putc(m, '\n');
+                       for_each_ring(ring, dev_priv, i) {
+                               struct drm_i915_gem_object *ctx_obj =
+                                       ctx->engine[i].state;
+                               struct intel_ringbuffer *ringbuf =
+                                       ctx->engine[i].ringbuf;
+
+                               seq_printf(m, "%s: ", ring->name);
+                               if (ctx_obj)
+                                       describe_obj(m, ctx_obj);
+                               if (ringbuf)
+                                       describe_ctx_ringbuf(m, ringbuf);
+                               seq_putc(m, '\n');
+                       }
+               } else {
+                       describe_obj(m, ctx->legacy_hw_ctx.rcs_state);
+               }
+
+               seq_putc(m, '\n');
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static int i915_dump_lrc(struct seq_file *m, void *unused)
+{
+       struct drm_info_node *node = (struct drm_info_node *) m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring;
+       struct intel_context *ctx;
+       int ret, i;
+
+       if (!i915.enable_execlists) {
+               seq_printf(m, "Logical Ring Contexts are disabled\n");
+               return 0;
+       }
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       list_for_each_entry(ctx, &dev_priv->context_list, link) {
+               for_each_ring(ring, dev_priv, i) {
+                       struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state;
+
                        if (ring->default_context == ctx)
-                               seq_printf(m, "(default context %s) ", ring->name);
+                               continue;
+
+                       if (ctx_obj) {
+                               struct page *page = i915_gem_object_get_page(ctx_obj, 1);
+                               uint32_t *reg_state = kmap_atomic(page);
+                               int j;
+
+                               seq_printf(m, "CONTEXT: %s %u\n", ring->name,
+                                               intel_execlists_ctx_id(ctx_obj));
+
+                               for (j = 0; j < 0x600 / sizeof(u32) / 4; j += 4) {
+                                       seq_printf(m, "\t[0x%08lx] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+                                       i915_gem_obj_ggtt_offset(ctx_obj) + 4096 + (j * 4),
+                                       reg_state[j], reg_state[j + 1],
+                                       reg_state[j + 2], reg_state[j + 3]);
+                               }
+                               kunmap_atomic(reg_state);
+
+                               seq_putc(m, '\n');
+                       }
+               }
+       }
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
+static int i915_execlists(struct seq_file *m, void *data)
+{
+       struct drm_info_node *node = (struct drm_info_node *)m->private;
+       struct drm_device *dev = node->minor->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring;
+       u32 status_pointer;
+       u8 read_pointer;
+       u8 write_pointer;
+       u32 status;
+       u32 ctx_id;
+       struct list_head *cursor;
+       int ring_id, i;
+       int ret;
+
+       if (!i915.enable_execlists) {
+               seq_puts(m, "Logical Ring Contexts are disabled\n");
+               return 0;
+       }
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       for_each_ring(ring, dev_priv, ring_id) {
+               struct intel_ctx_submit_request *head_req = NULL;
+               int count = 0;
+               unsigned long flags;
+
+               seq_printf(m, "%s\n", ring->name);
+
+               status = I915_READ(RING_EXECLIST_STATUS(ring));
+               ctx_id = I915_READ(RING_EXECLIST_STATUS(ring) + 4);
+               seq_printf(m, "\tExeclist status: 0x%08X, context: %u\n",
+                          status, ctx_id);
+
+               status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring));
+               seq_printf(m, "\tStatus pointer: 0x%08X\n", status_pointer);
+
+               read_pointer = ring->next_context_status_buffer;
+               write_pointer = status_pointer & 0x07;
+               if (read_pointer > write_pointer)
+                       write_pointer += 6;
+               seq_printf(m, "\tRead pointer: 0x%08X, write pointer 0x%08X\n",
+                          read_pointer, write_pointer);
+
+               for (i = 0; i < 6; i++) {
+                       status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + 8*i);
+                       ctx_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) + 8*i + 4);
+
+                       seq_printf(m, "\tStatus buffer %d: 0x%08X, context: %u\n",
+                                  i, status, ctx_id);
+               }
+
+               spin_lock_irqsave(&ring->execlist_lock, flags);
+               list_for_each(cursor, &ring->execlist_queue)
+                       count++;
+               head_req = list_first_entry_or_null(&ring->execlist_queue,
+                               struct intel_ctx_submit_request, execlist_link);
+               spin_unlock_irqrestore(&ring->execlist_lock, flags);
+
+               seq_printf(m, "\t%d requests in queue\n", count);
+               if (head_req) {
+                       struct drm_i915_gem_object *ctx_obj;
+
+                       ctx_obj = head_req->ctx->engine[ring_id].state;
+                       seq_printf(m, "\tHead request id: %u\n",
+                                  intel_execlists_ctx_id(ctx_obj));
+                       seq_printf(m, "\tHead request tail: %u\n",
+                                  head_req->tail);
+               }
 
-               describe_obj(m, ctx->legacy_hw_ctx.rcs_state);
                seq_putc(m, '\n');
        }
 
@@ -1815,7 +1981,13 @@ static int per_file_ctx(int id, void *ptr, void *data)
 {
        struct intel_context *ctx = ptr;
        struct seq_file *m = data;
-       struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(ctx);
+       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;
+
+       if (!ppgtt) {
+               seq_printf(m, "  no ppgtt for context %d\n",
+                          ctx->user_handle);
+               return 0;
+       }
 
        if (i915_gem_context_is_default(ctx))
                seq_puts(m, "  default context:\n");
@@ -1875,8 +2047,7 @@ static void gen6_ppgtt_info(struct seq_file *m, struct drm_device *dev)
                seq_printf(m, "pd gtt offset: 0x%08x\n", ppgtt->pd_offset);
 
                ppgtt->debug_dump(ppgtt, m);
-       } else
-               return;
+       }
 
        list_for_each_entry_reverse(file, &dev->filelist, lhead) {
                struct drm_i915_file_private *file_priv = file->driver_priv;
@@ -3963,6 +4134,8 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_opregion", i915_opregion, 0},
        {"i915_gem_framebuffer", i915_gem_framebuffer_info, 0},
        {"i915_context_status", i915_context_status, 0},
+       {"i915_dump_lrc", i915_dump_lrc, 0},
+       {"i915_execlists", i915_execlists, 0},
        {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
        {"i915_swizzle_info", i915_swizzle_info, 0},
        {"i915_ppgtt_info", i915_ppgtt_info, 0},
index c965698a8baceaa2a298d9f7a7c8c4df5c6cd2aa..3f676f904f7e34f3298ee91b63c782ef107dafdb 100644 (file)
@@ -999,7 +999,7 @@ static int i915_getparam(struct drm_device *dev, void *data,
                value = HAS_WT(dev);
                break;
        case I915_PARAM_HAS_ALIASING_PPGTT:
-               value = dev_priv->mm.aliasing_ppgtt || USES_FULL_PPGTT(dev);
+               value = USES_PPGTT(dev);
                break;
        case I915_PARAM_HAS_WAIT_TIMEOUT:
                value = 1;
@@ -1350,8 +1350,6 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto cleanup_irq;
 
-       INIT_WORK(&dev_priv->console_resume_work, intel_console_resume);
-
        intel_modeset_gem_init(dev);
 
        /* Always safe in the mode setting case. */
@@ -1388,7 +1386,6 @@ cleanup_gem:
        i915_gem_cleanup_ringbuffer(dev);
        i915_gem_context_fini(dev);
        mutex_unlock(&dev->struct_mutex);
-       WARN_ON(dev_priv->mm.aliasing_ppgtt);
 cleanup_irq:
        drm_irq_uninstall(dev);
 cleanup_gem_stolen:
@@ -1603,9 +1600,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        dev->dev_private = dev_priv;
        dev_priv->dev = dev;
 
-       /* copy initial configuration to dev_priv->info */
+       /* Setup the write-once "constant" device info */
        device_info = (struct intel_device_info *)&dev_priv->info;
-       *device_info = *info;
+       memcpy(device_info, info, sizeof(dev_priv->info));
+       device_info->device_id = dev->pdev->device;
 
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->gpu_error.lock);
@@ -1817,7 +1815,7 @@ out_mtrrfree:
        arch_phys_wc_del(dev_priv->gtt.mtrr);
        io_mapping_free(dev_priv->gtt.mappable);
 out_gtt:
-       dev_priv->gtt.base.cleanup(&dev_priv->gtt.base);
+       i915_global_gtt_cleanup(dev);
 out_regs:
        intel_uncore_fini(dev);
        pci_iounmap(dev->pdev, dev_priv->regs);
@@ -1864,7 +1862,6 @@ int i915_driver_unload(struct drm_device *dev)
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                intel_fbdev_fini(dev);
                intel_modeset_cleanup(dev);
-               cancel_work_sync(&dev_priv->console_resume_work);
 
                /*
                 * free the memory space allocated for the child device
@@ -1897,7 +1894,6 @@ int i915_driver_unload(struct drm_device *dev)
                mutex_lock(&dev->struct_mutex);
                i915_gem_cleanup_ringbuffer(dev);
                i915_gem_context_fini(dev);
-               WARN_ON(dev_priv->mm.aliasing_ppgtt);
                mutex_unlock(&dev->struct_mutex);
                i915_gem_cleanup_stolen(dev);
 
@@ -1905,8 +1901,6 @@ int i915_driver_unload(struct drm_device *dev)
                        i915_free_hws(dev);
        }
 
-       WARN_ON(!list_empty(&dev_priv->vm_list));
-
        drm_vblank_cleanup(dev);
 
        intel_teardown_gmbus(dev);
@@ -1916,7 +1910,7 @@ int i915_driver_unload(struct drm_device *dev)
        destroy_workqueue(dev_priv->wq);
        pm_qos_remove_request(&dev_priv->pm_qos);
 
-       dev_priv->gtt.base.cleanup(&dev_priv->gtt.base);
+       i915_global_gtt_cleanup(dev);
 
        intel_uncore_fini(dev);
        if (dev_priv->regs != NULL)
index e27cdbe9d524a79dbd4168febc15de0660e82d9f..ff4db249cc7210f16169cc9d6a4c4413e9f70104 100644 (file)
@@ -481,6 +481,10 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
        if (i915.semaphores >= 0)
                return i915.semaphores;
 
+       /* TODO: make semaphores and Execlists play nicely together */
+       if (i915.enable_execlists)
+               return false;
+
        /* Until we get further testing... */
        if (IS_GEN8(dev))
                return false;
@@ -524,6 +528,10 @@ static void intel_suspend_encoders(struct drm_i915_private *dev_priv)
        drm_modeset_unlock_all(dev);
 }
 
+static int intel_suspend_complete(struct drm_i915_private *dev_priv);
+static int intel_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume);
+
 static int i915_drm_freeze(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -591,9 +599,7 @@ static int i915_drm_freeze(struct drm_device *dev)
        intel_uncore_forcewake_reset(dev, false);
        intel_opregion_fini(dev);
 
-       console_lock();
-       intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED);
-       console_unlock();
+       intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true);
 
        dev_priv->suspend_count++;
 
@@ -632,30 +638,20 @@ int i915_suspend(struct drm_device *dev, pm_message_t state)
        return 0;
 }
 
-void intel_console_resume(struct work_struct *work)
-{
-       struct drm_i915_private *dev_priv =
-               container_of(work, struct drm_i915_private,
-                            console_resume_work);
-       struct drm_device *dev = dev_priv->dev;
-
-       console_lock();
-       intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
-       console_unlock();
-}
-
 static int i915_drm_thaw_early(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
 
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-               hsw_disable_pc8(dev_priv);
+       ret = intel_resume_prepare(dev_priv, false);
+       if (ret)
+               DRM_ERROR("Resume prepare failed: %d,Continuing resume\n", ret);
 
        intel_uncore_early_sanitize(dev, true);
        intel_uncore_sanitize(dev);
        intel_power_domains_init_hw(dev_priv);
 
-       return 0;
+       return ret;
 }
 
 static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
@@ -714,17 +710,7 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
 
        intel_opregion_init(dev);
 
-       /*
-        * The console lock can be pretty contented on resume due
-        * to all the printk activity.  Try to keep it out of the hot
-        * path of resume if possible.
-        */
-       if (console_trylock()) {
-               intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING);
-               console_unlock();
-       } else {
-               schedule_work(&dev_priv->console_resume_work);
-       }
+       intel_fbdev_set_suspend(dev, FBINFO_STATE_RUNNING, false);
 
        mutex_lock(&dev_priv->modeset_restore_lock);
        dev_priv->modeset_restore = MODESET_DONE;
@@ -941,6 +927,7 @@ static int i915_pm_suspend_late(struct device *dev)
        struct pci_dev *pdev = to_pci_dev(dev);
        struct drm_device *drm_dev = pci_get_drvdata(pdev);
        struct drm_i915_private *dev_priv = drm_dev->dev_private;
+       int ret;
 
        /*
         * We have a suspedn ordering issue with the snd-hda driver also
@@ -954,13 +941,16 @@ static int i915_pm_suspend_late(struct device *dev)
        if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
                return 0;
 
-       if (IS_HASWELL(drm_dev) || IS_BROADWELL(drm_dev))
-               hsw_enable_pc8(dev_priv);
+       ret = intel_suspend_complete(dev_priv);
 
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
+       if (ret)
+               DRM_ERROR("Suspend complete failed: %d\n", ret);
+       else {
+               pci_disable_device(pdev);
+               pci_set_power_state(pdev, PCI_D3hot);
+       }
 
-       return 0;
+       return ret;
 }
 
 static int i915_pm_resume_early(struct device *dev)
@@ -1016,23 +1006,26 @@ static int i915_pm_poweroff(struct device *dev)
        return i915_drm_freeze(drm_dev);
 }
 
-static int hsw_runtime_suspend(struct drm_i915_private *dev_priv)
+static int hsw_suspend_complete(struct drm_i915_private *dev_priv)
 {
        hsw_enable_pc8(dev_priv);
 
        return 0;
 }
 
-static int snb_runtime_resume(struct drm_i915_private *dev_priv)
+static int snb_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume)
 {
        struct drm_device *dev = dev_priv->dev;
 
-       intel_init_pch_refclk(dev);
+       if (rpm_resume)
+               intel_init_pch_refclk(dev);
 
        return 0;
 }
 
-static int hsw_runtime_resume(struct drm_i915_private *dev_priv)
+static int hsw_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume)
 {
        hsw_disable_pc8(dev_priv);
 
@@ -1328,7 +1321,7 @@ static void vlv_check_no_gt_access(struct drm_i915_private *dev_priv)
        I915_WRITE(VLV_GTLC_PW_STATUS, VLV_GTLC_ALLOWWAKEERR);
 }
 
-static int vlv_runtime_suspend(struct drm_i915_private *dev_priv)
+static int vlv_suspend_complete(struct drm_i915_private *dev_priv)
 {
        u32 mask;
        int err;
@@ -1368,7 +1361,8 @@ err1:
        return err;
 }
 
-static int vlv_runtime_resume(struct drm_i915_private *dev_priv)
+static int vlv_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume)
 {
        struct drm_device *dev = dev_priv->dev;
        int err;
@@ -1393,8 +1387,10 @@ static int vlv_runtime_resume(struct drm_i915_private *dev_priv)
 
        vlv_check_no_gt_access(dev_priv);
 
-       intel_init_clock_gating(dev);
-       i915_gem_restore_fences(dev);
+       if (rpm_resume) {
+               intel_init_clock_gating(dev);
+               i915_gem_restore_fences(dev);
+       }
 
        return ret;
 }
@@ -1409,7 +1405,9 @@ static int intel_runtime_suspend(struct device *device)
        if (WARN_ON_ONCE(!(dev_priv->rps.enabled && intel_enable_rc6(dev))))
                return -ENODEV;
 
-       WARN_ON(!HAS_RUNTIME_PM(dev));
+       if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev)))
+               return -ENODEV;
+
        assert_force_wake_inactive(dev_priv);
 
        DRM_DEBUG_KMS("Suspending device\n");
@@ -1446,17 +1444,7 @@ static int intel_runtime_suspend(struct device *device)
        cancel_work_sync(&dev_priv->rps.work);
        intel_runtime_pm_disable_interrupts(dev);
 
-       if (IS_GEN6(dev)) {
-               ret = 0;
-       } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
-               ret = hsw_runtime_suspend(dev_priv);
-       } else if (IS_VALLEYVIEW(dev)) {
-               ret = vlv_runtime_suspend(dev_priv);
-       } else {
-               ret = -ENODEV;
-               WARN_ON(1);
-       }
-
+       ret = intel_suspend_complete(dev_priv);
        if (ret) {
                DRM_ERROR("Runtime suspend failed, disabling it (%d)\n", ret);
                intel_runtime_pm_restore_interrupts(dev);
@@ -1487,24 +1475,15 @@ static int intel_runtime_resume(struct device *device)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
-       WARN_ON(!HAS_RUNTIME_PM(dev));
+       if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev)))
+               return -ENODEV;
 
        DRM_DEBUG_KMS("Resuming device\n");
 
        intel_opregion_notify_adapter(dev, PCI_D0);
        dev_priv->pm.suspended = false;
 
-       if (IS_GEN6(dev)) {
-               ret = snb_runtime_resume(dev_priv);
-       } else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
-               ret = hsw_runtime_resume(dev_priv);
-       } else if (IS_VALLEYVIEW(dev)) {
-               ret = vlv_runtime_resume(dev_priv);
-       } else {
-               WARN_ON(1);
-               ret = -ENODEV;
-       }
-
+       ret = intel_resume_prepare(dev_priv, true);
        /*
         * No point of rolling back things in case of an error, as the best
         * we can do is to hope that things will still work (and disable RPM).
@@ -1523,6 +1502,48 @@ static int intel_runtime_resume(struct device *device)
        return ret;
 }
 
+/*
+ * This function implements common functionality of runtime and system
+ * suspend sequence.
+ */
+static int intel_suspend_complete(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       int ret;
+
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               ret = hsw_suspend_complete(dev_priv);
+       else if (IS_VALLEYVIEW(dev))
+               ret = vlv_suspend_complete(dev_priv);
+       else
+               ret = 0;
+
+       return ret;
+}
+
+/*
+ * This function implements common functionality of runtime and system
+ * resume sequence. Variable rpm_resume used for implementing different
+ * code paths.
+ */
+static int intel_resume_prepare(struct drm_i915_private *dev_priv,
+                               bool rpm_resume)
+{
+       struct drm_device *dev = dev_priv->dev;
+       int ret;
+
+       if (IS_GEN6(dev))
+               ret = snb_resume_prepare(dev_priv, rpm_resume);
+       else if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               ret = hsw_resume_prepare(dev_priv, rpm_resume);
+       else if (IS_VALLEYVIEW(dev))
+               ret = vlv_resume_prepare(dev_priv, rpm_resume);
+       else
+               ret = 0;
+
+       return ret;
+}
+
 static const struct dev_pm_ops i915_pm_ops = {
        .suspend = i915_pm_suspend,
        .suspend_late = i915_pm_suspend_late,
index 0730af32afe6783e8fac7984e20c9454316777a7..bcf8783dbc2e79176dc82045e9222e395ef71490 100644 (file)
@@ -35,6 +35,7 @@
 #include "i915_reg.h"
 #include "intel_bios.h"
 #include "intel_ringbuffer.h"
+#include "intel_lrc.h"
 #include "i915_gem_gtt.h"
 #include <linux/io-mapping.h>
 #include <linux/i2c.h>
@@ -53,7 +54,7 @@
 
 #define DRIVER_NAME            "i915"
 #define DRIVER_DESC            "Intel Graphics"
-#define DRIVER_DATE            "20140808"
+#define DRIVER_DATE            "20140822"
 
 enum pipe {
        INVALID_PIPE = -1,
@@ -395,6 +396,7 @@ struct drm_i915_error_state {
                pid_t pid;
                char comm[TASK_COMM_LEN];
        } ring[I915_NUM_RINGS];
+
        struct drm_i915_error_buffer {
                u32 size;
                u32 name;
@@ -413,6 +415,7 @@ struct drm_i915_error_state {
        } **active_bo, **pinned_bo;
 
        u32 *active_bo_count, *pinned_bo_count;
+       u32 vm_count;
 };
 
 struct intel_connector;
@@ -558,6 +561,7 @@ struct intel_uncore {
 
 struct intel_device_info {
        u32 display_mmio_offset;
+       u16 device_id;
        u8 num_pipes:3;
        u8 num_sprites[I915_MAX_PIPES];
        u8 gen;
@@ -622,13 +626,20 @@ struct intel_context {
        uint8_t remap_slice;
        struct drm_i915_file_private *file_priv;
        struct i915_ctx_hang_stats hang_stats;
-       struct i915_address_space *vm;
+       struct i915_hw_ppgtt *ppgtt;
 
+       /* Legacy ring buffer submission */
        struct {
                struct drm_i915_gem_object *rcs_state;
                bool initialized;
        } legacy_hw_ctx;
 
+       /* Execlists */
+       struct {
+               struct drm_i915_gem_object *state;
+               struct intel_ringbuffer *ringbuf;
+       } engine[I915_NUM_RINGS];
+
        struct list_head link;
 };
 
@@ -1577,14 +1588,9 @@ struct drm_i915_private {
 #ifdef CONFIG_DRM_I915_FBDEV
        /* list of fbdev register on this device */
        struct intel_fbdev *fbdev;
+       struct work_struct fbdev_suspend_work;
 #endif
 
-       /*
-        * The console may be contended at resume, but we don't
-        * want it to block on it.
-        */
-       struct work_struct console_resume_work;
-
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 
@@ -1636,6 +1642,20 @@ struct drm_i915_private {
        /* Old ums support infrastructure, same warning applies. */
        struct i915_ums_state ums;
 
+       /* Abstract the submission mechanism (legacy ringbuffer or execlists) away */
+       struct {
+               int (*do_execbuf)(struct drm_device *dev, struct drm_file *file,
+                                 struct intel_engine_cs *ring,
+                                 struct intel_context *ctx,
+                                 struct drm_i915_gem_execbuffer2 *args,
+                                 struct list_head *vmas,
+                                 struct drm_i915_gem_object *batch_obj,
+                                 u64 exec_start, u32 flags);
+               int (*init_rings)(struct drm_device *dev);
+               void (*cleanup_ring)(struct intel_engine_cs *ring);
+               void (*stop_ring)(struct intel_engine_cs *ring);
+       } gt;
+
        /*
         * NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
         * will be rejected. Instead look for a better place.
@@ -1777,13 +1797,6 @@ struct drm_i915_gem_object {
         * Only honoured if hardware has relevant pte bit
         */
        unsigned long gt_ro:1;
-
-       /*
-        * Is the GPU currently using a fence to access this buffer,
-        */
-       unsigned int pending_fenced_gpu_access:1;
-       unsigned int fenced_gpu_access:1;
-
        unsigned int cache_level:3;
 
        unsigned int has_aliasing_ppgtt_mapping:1;
@@ -1987,51 +2000,63 @@ struct drm_i915_cmd_table {
        int count;
 };
 
-#define INTEL_INFO(dev)        (&to_i915(dev)->info)
-
-#define IS_I830(dev)           ((dev)->pdev->device == 0x3577)
-#define IS_845G(dev)           ((dev)->pdev->device == 0x2562)
+/* Note that the (struct drm_i915_private *) cast is just to shut up gcc. */
+#define __I915__(p) ({ \
+       struct drm_i915_private *__p; \
+       if (__builtin_types_compatible_p(typeof(*p), struct drm_i915_private)) \
+               __p = (struct drm_i915_private *)p; \
+       else if (__builtin_types_compatible_p(typeof(*p), struct drm_device)) \
+               __p = to_i915((struct drm_device *)p); \
+       else \
+               BUILD_BUG(); \
+       __p; \
+})
+#define INTEL_INFO(p)  (&__I915__(p)->info)
+#define INTEL_DEVID(p) (INTEL_INFO(p)->device_id)
+
+#define IS_I830(dev)           (INTEL_DEVID(dev) == 0x3577)
+#define IS_845G(dev)           (INTEL_DEVID(dev) == 0x2562)
 #define IS_I85X(dev)           (INTEL_INFO(dev)->is_i85x)
-#define IS_I865G(dev)          ((dev)->pdev->device == 0x2572)
+#define IS_I865G(dev)          (INTEL_DEVID(dev) == 0x2572)
 #define IS_I915G(dev)          (INTEL_INFO(dev)->is_i915g)
-#define IS_I915GM(dev)         ((dev)->pdev->device == 0x2592)
-#define IS_I945G(dev)          ((dev)->pdev->device == 0x2772)
+#define IS_I915GM(dev)         (INTEL_DEVID(dev) == 0x2592)
+#define IS_I945G(dev)          (INTEL_DEVID(dev) == 0x2772)
 #define IS_I945GM(dev)         (INTEL_INFO(dev)->is_i945gm)
 #define IS_BROADWATER(dev)     (INTEL_INFO(dev)->is_broadwater)
 #define IS_CRESTLINE(dev)      (INTEL_INFO(dev)->is_crestline)
-#define IS_GM45(dev)           ((dev)->pdev->device == 0x2A42)
+#define IS_GM45(dev)           (INTEL_DEVID(dev) == 0x2A42)
 #define IS_G4X(dev)            (INTEL_INFO(dev)->is_g4x)
-#define IS_PINEVIEW_G(dev)     ((dev)->pdev->device == 0xa001)
-#define IS_PINEVIEW_M(dev)     ((dev)->pdev->device == 0xa011)
+#define IS_PINEVIEW_G(dev)     (INTEL_DEVID(dev) == 0xa001)
+#define IS_PINEVIEW_M(dev)     (INTEL_DEVID(dev) == 0xa011)
 #define IS_PINEVIEW(dev)       (INTEL_INFO(dev)->is_pineview)
 #define IS_G33(dev)            (INTEL_INFO(dev)->is_g33)
-#define IS_IRONLAKE_M(dev)     ((dev)->pdev->device == 0x0046)
+#define IS_IRONLAKE_M(dev)     (INTEL_DEVID(dev) == 0x0046)
 #define IS_IVYBRIDGE(dev)      (INTEL_INFO(dev)->is_ivybridge)
-#define IS_IVB_GT1(dev)                ((dev)->pdev->device == 0x0156 || \
-                                (dev)->pdev->device == 0x0152 || \
-                                (dev)->pdev->device == 0x015a)
-#define IS_SNB_GT1(dev)                ((dev)->pdev->device == 0x0102 || \
-                                (dev)->pdev->device == 0x0106 || \
-                                (dev)->pdev->device == 0x010A)
+#define IS_IVB_GT1(dev)                (INTEL_DEVID(dev) == 0x0156 || \
+                                INTEL_DEVID(dev) == 0x0152 || \
+                                INTEL_DEVID(dev) == 0x015a)
+#define IS_SNB_GT1(dev)                (INTEL_DEVID(dev) == 0x0102 || \
+                                INTEL_DEVID(dev) == 0x0106 || \
+                                INTEL_DEVID(dev) == 0x010A)
 #define IS_VALLEYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview)
 #define IS_CHERRYVIEW(dev)     (INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
 #define IS_HASWELL(dev)        (INTEL_INFO(dev)->is_haswell)
 #define IS_BROADWELL(dev)      (!INTEL_INFO(dev)->is_valleyview && IS_GEN8(dev))
 #define IS_MOBILE(dev)         (INTEL_INFO(dev)->is_mobile)
 #define IS_HSW_EARLY_SDV(dev)  (IS_HASWELL(dev) && \
-                                ((dev)->pdev->device & 0xFF00) == 0x0C00)
+                                (INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
 #define IS_BDW_ULT(dev)                (IS_BROADWELL(dev) && \
-                                (((dev)->pdev->device & 0xf) == 0x2  || \
-                                ((dev)->pdev->device & 0xf) == 0x6 || \
-                                ((dev)->pdev->device & 0xf) == 0xe))
+                                ((INTEL_DEVID(dev) & 0xf) == 0x2  || \
+                                (INTEL_DEVID(dev) & 0xf) == 0x6 || \
+                                (INTEL_DEVID(dev) & 0xf) == 0xe))
 #define IS_HSW_ULT(dev)                (IS_HASWELL(dev) && \
-                                ((dev)->pdev->device & 0xFF00) == 0x0A00)
+                                (INTEL_DEVID(dev) & 0xFF00) == 0x0A00)
 #define IS_ULT(dev)            (IS_HSW_ULT(dev) || IS_BDW_ULT(dev))
 #define IS_HSW_GT3(dev)                (IS_HASWELL(dev) && \
-                                ((dev)->pdev->device & 0x00F0) == 0x0020)
+                                (INTEL_DEVID(dev) & 0x00F0) == 0x0020)
 /* ULX machines are also considered ULT. */
-#define IS_HSW_ULX(dev)                ((dev)->pdev->device == 0x0A0E || \
-                                (dev)->pdev->device == 0x0A1E)
+#define IS_HSW_ULX(dev)                (INTEL_DEVID(dev) == 0x0A0E || \
+                                INTEL_DEVID(dev) == 0x0A1E)
 #define IS_PRELIMINARY_HW(intel_info) ((intel_info)->is_preliminary)
 
 /*
@@ -2063,6 +2088,7 @@ struct drm_i915_cmd_table {
 #define I915_NEED_GFX_HWS(dev) (INTEL_INFO(dev)->need_gfx_hws)
 
 #define HAS_HW_CONTEXTS(dev)   (INTEL_INFO(dev)->gen >= 6)
+#define HAS_LOGICAL_RING_CONTEXTS(dev) (INTEL_INFO(dev)->gen >= 8)
 #define HAS_ALIASING_PPGTT(dev)        (INTEL_INFO(dev)->gen >= 6)
 #define HAS_PPGTT(dev)         (INTEL_INFO(dev)->gen >= 7 && !IS_GEN8(dev))
 #define USES_PPGTT(dev)                (i915.enable_ppgtt)
@@ -2150,6 +2176,7 @@ struct i915_params {
        int enable_rc6;
        int enable_fbc;
        int enable_ppgtt;
+       int enable_execlists;
        int enable_psr;
        unsigned int preliminary_hw_support;
        int disable_power_well;
@@ -2196,8 +2223,6 @@ extern void i915_update_gfx_val(struct drm_i915_private *dev_priv);
 int vlv_force_gfx_clock(struct drm_i915_private *dev_priv, bool on);
 void intel_hpd_cancel_work(struct drm_i915_private *dev_priv);
 
-extern void intel_console_resume(struct work_struct *work);
-
 /* i915_irq.c */
 void i915_queue_hangcheck(struct drm_device *dev);
 __printf(3, 4)
@@ -2245,6 +2270,20 @@ int i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
                              struct drm_file *file_priv);
 int i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
                             struct drm_file *file_priv);
+void i915_gem_execbuffer_move_to_active(struct list_head *vmas,
+                                       struct intel_engine_cs *ring);
+void i915_gem_execbuffer_retire_commands(struct drm_device *dev,
+                                        struct drm_file *file,
+                                        struct intel_engine_cs *ring,
+                                        struct drm_i915_gem_object *obj);
+int i915_gem_ringbuffer_submission(struct drm_device *dev,
+                                  struct drm_file *file,
+                                  struct intel_engine_cs *ring,
+                                  struct intel_context *ctx,
+                                  struct drm_i915_gem_execbuffer2 *args,
+                                  struct list_head *vmas,
+                                  struct drm_i915_gem_object *batch_obj,
+                                  u64 exec_start, u32 flags);
 int i915_gem_execbuffer(struct drm_device *dev, void *data,
                        struct drm_file *file_priv);
 int i915_gem_execbuffer2(struct drm_device *dev, void *data,
@@ -2397,6 +2436,7 @@ void i915_gem_reset(struct drm_device *dev);
 bool i915_gem_clflush_object(struct drm_i915_gem_object *obj, bool force);
 int __must_check i915_gem_object_finish_gpu(struct drm_i915_gem_object *obj);
 int __must_check i915_gem_init(struct drm_device *dev);
+int i915_gem_init_rings(struct drm_device *dev);
 int __must_check i915_gem_init_hw(struct drm_device *dev);
 int i915_gem_l3_remap(struct intel_engine_cs *ring, int slice);
 void i915_gem_init_swizzling(struct drm_device *dev);
@@ -2467,7 +2507,7 @@ static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
 }
 
 /* Some GGTT VM helpers */
-#define obj_to_ggtt(obj) \
+#define i915_obj_to_ggtt(obj) \
        (&((struct drm_i915_private *)(obj)->base.dev->dev_private)->gtt.base)
 static inline bool i915_is_ggtt(struct i915_address_space *vm)
 {
@@ -2476,21 +2516,30 @@ static inline bool i915_is_ggtt(struct i915_address_space *vm)
        return vm == ggtt;
 }
 
+static inline struct i915_hw_ppgtt *
+i915_vm_to_ppgtt(struct i915_address_space *vm)
+{
+       WARN_ON(i915_is_ggtt(vm));
+
+       return container_of(vm, struct i915_hw_ppgtt, base);
+}
+
+
 static inline bool i915_gem_obj_ggtt_bound(struct drm_i915_gem_object *obj)
 {
-       return i915_gem_obj_bound(obj, obj_to_ggtt(obj));
+       return i915_gem_obj_bound(obj, i915_obj_to_ggtt(obj));
 }
 
 static inline unsigned long
 i915_gem_obj_ggtt_offset(struct drm_i915_gem_object *obj)
 {
-       return i915_gem_obj_offset(obj, obj_to_ggtt(obj));
+       return i915_gem_obj_offset(obj, i915_obj_to_ggtt(obj));
 }
 
 static inline unsigned long
 i915_gem_obj_ggtt_size(struct drm_i915_gem_object *obj)
 {
-       return i915_gem_obj_size(obj, obj_to_ggtt(obj));
+       return i915_gem_obj_size(obj, i915_obj_to_ggtt(obj));
 }
 
 static inline int __must_check
@@ -2498,7 +2547,8 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj,
                      uint32_t alignment,
                      unsigned flags)
 {
-       return i915_gem_object_pin(obj, obj_to_ggtt(obj), alignment, flags | PIN_GLOBAL);
+       return i915_gem_object_pin(obj, i915_obj_to_ggtt(obj),
+                                  alignment, flags | PIN_GLOBAL);
 }
 
 static inline int
@@ -2510,7 +2560,6 @@ i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj)
 void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj);
 
 /* i915_gem_context.c */
-#define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base)
 int __must_check i915_gem_context_init(struct drm_device *dev);
 void i915_gem_context_fini(struct drm_device *dev);
 void i915_gem_context_reset(struct drm_device *dev);
@@ -2522,6 +2571,8 @@ int i915_switch_context(struct intel_engine_cs *ring,
 struct intel_context *
 i915_gem_context_get(struct drm_i915_file_private *file_priv, u32 id);
 void i915_gem_context_free(struct kref *ctx_ref);
+struct drm_i915_gem_object *
+i915_gem_alloc_context_obj(struct drm_device *dev, size_t size);
 static inline void i915_gem_context_reference(struct intel_context *ctx)
 {
        kref_get(&ctx->ref);
index ba7f5c6bb50d1f7e5b886ea20e74ed58a9ae5247..f1bb69377a356db36c105fdf84b615fdbe03dd23 100644 (file)
@@ -2160,8 +2160,6 @@ static void
 i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
                               struct intel_engine_cs *ring)
 {
-       struct drm_device *dev = obj->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        u32 seqno = intel_ring_get_seqno(ring);
 
        BUG_ON(ring == NULL);
@@ -2180,19 +2178,6 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
        list_move_tail(&obj->ring_list, &ring->active_list);
 
        obj->last_read_seqno = seqno;
-
-       if (obj->fenced_gpu_access) {
-               obj->last_fenced_seqno = seqno;
-
-               /* Bump MRU to take account of the delayed flush */
-               if (obj->fence_reg != I915_FENCE_REG_NONE) {
-                       struct drm_i915_fence_reg *reg;
-
-                       reg = &dev_priv->fence_regs[obj->fence_reg];
-                       list_move_tail(&reg->lru_list,
-                                      &dev_priv->mm.fence_list);
-               }
-       }
 }
 
 void i915_vma_move_to_active(struct i915_vma *vma,
@@ -2228,7 +2213,6 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
        obj->base.write_domain = 0;
 
        obj->last_fenced_seqno = 0;
-       obj->fenced_gpu_access = false;
 
        obj->active = 0;
        drm_gem_object_unreference(&obj->base);
@@ -2326,10 +2310,21 @@ int __i915_add_request(struct intel_engine_cs *ring,
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct drm_i915_gem_request *request;
+       struct intel_ringbuffer *ringbuf;
        u32 request_ring_position, request_start;
        int ret;
 
-       request_start = intel_ring_get_tail(ring->buffer);
+       request = ring->preallocated_lazy_request;
+       if (WARN_ON(request == NULL))
+               return -ENOMEM;
+
+       if (i915.enable_execlists) {
+               struct intel_context *ctx = request->ctx;
+               ringbuf = ctx->engine[ring->id].ringbuf;
+       } else
+               ringbuf = ring->buffer;
+
+       request_start = intel_ring_get_tail(ringbuf);
        /*
         * Emit any outstanding flushes - execbuf can fail to emit the flush
         * after having emitted the batchbuffer command. Hence we need to fix
@@ -2337,24 +2332,32 @@ int __i915_add_request(struct intel_engine_cs *ring,
         * is that the flush _must_ happen before the next request, no matter
         * what.
         */
-       ret = intel_ring_flush_all_caches(ring);
-       if (ret)
-               return ret;
-
-       request = ring->preallocated_lazy_request;
-       if (WARN_ON(request == NULL))
-               return -ENOMEM;
+       if (i915.enable_execlists) {
+               ret = logical_ring_flush_all_caches(ringbuf);
+               if (ret)
+                       return ret;
+       } else {
+               ret = intel_ring_flush_all_caches(ring);
+               if (ret)
+                       return ret;
+       }
 
        /* Record the position of the start of the request so that
         * should we detect the updated seqno part-way through the
         * GPU processing the request, we never over-estimate the
         * position of the head.
         */
-       request_ring_position = intel_ring_get_tail(ring->buffer);
+       request_ring_position = intel_ring_get_tail(ringbuf);
 
-       ret = ring->add_request(ring);
-       if (ret)
-               return ret;
+       if (i915.enable_execlists) {
+               ret = ring->emit_request(ringbuf);
+               if (ret)
+                       return ret;
+       } else {
+               ret = ring->add_request(ring);
+               if (ret)
+                       return ret;
+       }
 
        request->seqno = intel_ring_get_seqno(ring);
        request->ring = ring;
@@ -2369,12 +2372,14 @@ int __i915_add_request(struct intel_engine_cs *ring,
         */
        request->batch_obj = obj;
 
-       /* Hold a reference to the current context so that we can inspect
-        * it later in case a hangcheck error event fires.
-        */
-       request->ctx = ring->last_context;
-       if (request->ctx)
-               i915_gem_context_reference(request->ctx);
+       if (!i915.enable_execlists) {
+               /* Hold a reference to the current context so that we can inspect
+                * it later in case a hangcheck error event fires.
+                */
+               request->ctx = ring->last_context;
+               if (request->ctx)
+                       i915_gem_context_reference(request->ctx);
+       }
 
        request->emitted_jiffies = jiffies;
        list_add_tail(&request->list, &ring->request_list);
@@ -2545,6 +2550,18 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
                i915_gem_free_request(request);
        }
 
+       while (!list_empty(&ring->execlist_queue)) {
+               struct intel_ctx_submit_request *submit_req;
+
+               submit_req = list_first_entry(&ring->execlist_queue,
+                               struct intel_ctx_submit_request,
+                               execlist_link);
+               list_del(&submit_req->execlist_link);
+               intel_runtime_pm_put(dev_priv);
+               i915_gem_context_unreference(submit_req->ctx);
+               kfree(submit_req);
+       }
+
        /* These may not have been flush before the reset, do so now */
        kfree(ring->preallocated_lazy_request);
        ring->preallocated_lazy_request = NULL;
@@ -2629,6 +2646,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
 
        while (!list_empty(&ring->request_list)) {
                struct drm_i915_gem_request *request;
+               struct intel_ringbuffer *ringbuf;
 
                request = list_first_entry(&ring->request_list,
                                           struct drm_i915_gem_request,
@@ -2638,12 +2656,24 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
                        break;
 
                trace_i915_gem_request_retire(ring, request->seqno);
+
+               /* This is one of the few common intersection points
+                * between legacy ringbuffer submission and execlists:
+                * we need to tell them apart in order to find the correct
+                * ringbuffer to which the request belongs to.
+                */
+               if (i915.enable_execlists) {
+                       struct intel_context *ctx = request->ctx;
+                       ringbuf = ctx->engine[ring->id].ringbuf;
+               } else
+                       ringbuf = ring->buffer;
+
                /* We know the GPU must have read the request to have
                 * sent us the seqno + interrupt, so use the position
                 * of tail of the request to update the last known position
                 * of the GPU head.
                 */
-               ring->buffer->last_retired_head = request->tail;
+               ringbuf->last_retired_head = request->tail;
 
                i915_gem_free_request(request);
        }
@@ -2919,9 +2949,8 @@ int i915_vma_unbind(struct i915_vma *vma)
        vma->unbind_vma(vma);
 
        list_del_init(&vma->mm_list);
-       /* Avoid an unnecessary call to unbind on rebind. */
        if (i915_is_ggtt(vma->vm))
-               obj->map_and_fenceable = true;
+               obj->map_and_fenceable = false;
 
        drm_mm_remove_node(&vma->node);
        i915_gem_vma_destroy(vma);
@@ -3166,7 +3195,6 @@ i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
                obj->last_fenced_seqno = 0;
        }
 
-       obj->fenced_gpu_access = false;
        return 0;
 }
 
@@ -3273,6 +3301,9 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
                        return 0;
                }
        } else if (enable) {
+               if (WARN_ON(!obj->map_and_fenceable))
+                       return -EINVAL;
+
                reg = i915_find_fence_reg(dev);
                if (IS_ERR(reg))
                        return PTR_ERR(reg);
@@ -3583,11 +3614,12 @@ int
 i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
 {
        struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
+       struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
        uint32_t old_write_domain, old_read_domains;
        int ret;
 
        /* Not valid to be called on unbound objects. */
-       if (!i915_gem_obj_bound_any(obj))
+       if (vma == NULL)
                return -EINVAL;
 
        if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
@@ -3629,13 +3661,9 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
                                            old_write_domain);
 
        /* And bump the LRU for this access */
-       if (i915_gem_object_is_inactive(obj)) {
-               struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
-               if (vma)
-                       list_move_tail(&vma->mm_list,
-                                      &dev_priv->gtt.base.inactive_list);
-
-       }
+       if (i915_gem_object_is_inactive(obj))
+               list_move_tail(&vma->mm_list,
+                              &dev_priv->gtt.base.inactive_list);
 
        return 0;
 }
@@ -3799,9 +3827,6 @@ static bool is_pin_display(struct drm_i915_gem_object *obj)
 {
        struct i915_vma *vma;
 
-       if (list_empty(&obj->vma_list))
-               return false;
-
        vma = i915_gem_obj_to_ggtt(obj);
        if (!vma)
                return false;
@@ -4328,8 +4353,6 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
 
        obj->fence_reg = I915_FENCE_REG_NONE;
        obj->madv = I915_MADV_WILLNEED;
-       /* Avoid an unnecessary call to unbind on the first bind. */
-       obj->map_and_fenceable = true;
 
        i915_gem_info_add_obj(obj->base.dev->dev_private, obj->base.size);
 }
@@ -4490,12 +4513,18 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
 
 void i915_gem_vma_destroy(struct i915_vma *vma)
 {
+       struct i915_address_space *vm = NULL;
        WARN_ON(vma->node.allocated);
 
        /* Keep the vma as a placeholder in the execbuffer reservation lists */
        if (!list_empty(&vma->exec_list))
                return;
 
+       vm = vma->vm;
+
+       if (!i915_is_ggtt(vm))
+               i915_ppgtt_put(i915_vm_to_ppgtt(vm));
+
        list_del(&vma->vma_link);
 
        kfree(vma);
@@ -4509,7 +4538,7 @@ i915_gem_stop_ringbuffers(struct drm_device *dev)
        int i;
 
        for_each_ring(ring, dev_priv, i)
-               intel_stop_ring_buffer(ring);
+               dev_priv->gt.stop_ring(ring);
 }
 
 int
@@ -4626,7 +4655,7 @@ intel_enable_blt(struct drm_device *dev)
        return true;
 }
 
-static int i915_gem_init_rings(struct drm_device *dev)
+int i915_gem_init_rings(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
@@ -4709,7 +4738,7 @@ i915_gem_init_hw(struct drm_device *dev)
 
        i915_gem_init_swizzling(dev);
 
-       ret = i915_gem_init_rings(dev);
+       ret = dev_priv->gt.init_rings(dev);
        if (ret)
                return ret;
 
@@ -4727,6 +4756,14 @@ i915_gem_init_hw(struct drm_device *dev)
        if (ret && ret != -EIO) {
                DRM_ERROR("Context enable failed %d\n", ret);
                i915_gem_cleanup_ringbuffer(dev);
+
+               return ret;
+       }
+
+       ret = i915_ppgtt_init_hw(dev);
+       if (ret && ret != -EIO) {
+               DRM_ERROR("PPGTT enable failed %d\n", ret);
+               i915_gem_cleanup_ringbuffer(dev);
        }
 
        return ret;
@@ -4737,6 +4774,9 @@ int i915_gem_init(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
+       i915.enable_execlists = intel_sanitize_enable_execlists(dev,
+                       i915.enable_execlists);
+
        mutex_lock(&dev->struct_mutex);
 
        if (IS_VALLEYVIEW(dev)) {
@@ -4747,7 +4787,24 @@ int i915_gem_init(struct drm_device *dev)
                        DRM_DEBUG_DRIVER("allow wake ack timed out\n");
        }
 
-       i915_gem_init_userptr(dev);
+       if (!i915.enable_execlists) {
+               dev_priv->gt.do_execbuf = i915_gem_ringbuffer_submission;
+               dev_priv->gt.init_rings = i915_gem_init_rings;
+               dev_priv->gt.cleanup_ring = intel_cleanup_ring_buffer;
+               dev_priv->gt.stop_ring = intel_stop_ring_buffer;
+       } else {
+               dev_priv->gt.do_execbuf = intel_execlists_submission;
+               dev_priv->gt.init_rings = intel_logical_rings_init;
+               dev_priv->gt.cleanup_ring = intel_logical_ring_cleanup;
+               dev_priv->gt.stop_ring = intel_logical_ring_stop;
+       }
+
+       ret = i915_gem_init_userptr(dev);
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
+
        i915_gem_init_global_gtt(dev);
 
        ret = i915_gem_context_init(dev);
@@ -4782,7 +4839,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
        int i;
 
        for_each_ring(ring, dev_priv, i)
-               intel_cleanup_ring_buffer(ring);
+               dev_priv->gt.cleanup_ring(ring);
 }
 
 int
@@ -5094,9 +5151,7 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
        struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
 
-       if (!dev_priv->mm.aliasing_ppgtt ||
-           vm == &dev_priv->mm.aliasing_ppgtt->base)
-               vm = &dev_priv->gtt.base;
+       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
 
        list_for_each_entry(vma, &o->vma_list, vma_link) {
                if (vma->vm == vm)
@@ -5137,9 +5192,7 @@ unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
        struct drm_i915_private *dev_priv = o->base.dev->dev_private;
        struct i915_vma *vma;
 
-       if (!dev_priv->mm.aliasing_ppgtt ||
-           vm == &dev_priv->mm.aliasing_ppgtt->base)
-               vm = &dev_priv->gtt.base;
+       WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
 
        BUG_ON(list_empty(&o->vma_list));
 
@@ -5244,14 +5297,8 @@ struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
 {
        struct i915_vma *vma;
 
-       /* This WARN has probably outlived its usefulness (callers already
-        * WARN if they don't find the GGTT vma they expect). When removing,
-        * remember to remove the pre-check in is_pin_display() as well */
-       if (WARN_ON(list_empty(&obj->vma_list)))
-               return NULL;
-
        vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link);
-       if (vma->vm != obj_to_ggtt(obj))
+       if (vma->vm != i915_obj_to_ggtt(obj))
                return NULL;
 
        return vma;
index 3b99390e467aa3bfabcfb99438d66981ec2509c0..9683e62ec61aa041e661daba39b167bb09e48d82 100644 (file)
 #define GEN6_CONTEXT_ALIGN (64<<10)
 #define GEN7_CONTEXT_ALIGN 4096
 
-static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
-{
-       struct drm_device *dev = ppgtt->base.dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct i915_address_space *vm = &ppgtt->base;
-
-       if (ppgtt == dev_priv->mm.aliasing_ppgtt ||
-           (list_empty(&vm->active_list) && list_empty(&vm->inactive_list))) {
-               ppgtt->base.cleanup(&ppgtt->base);
-               return;
-       }
-
-       /*
-        * Make sure vmas are unbound before we take down the drm_mm
-        *
-        * FIXME: Proper refcounting should take care of this, this shouldn't be
-        * needed at all.
-        */
-       if (!list_empty(&vm->active_list)) {
-               struct i915_vma *vma;
-
-               list_for_each_entry(vma, &vm->active_list, mm_list)
-                       if (WARN_ON(list_empty(&vma->vma_link) ||
-                                   list_is_singular(&vma->vma_link)))
-                               break;
-
-               i915_gem_evict_vm(&ppgtt->base, true);
-       } else {
-               i915_gem_retire_requests(dev);
-               i915_gem_evict_vm(&ppgtt->base, false);
-       }
-
-       ppgtt->base.cleanup(&ppgtt->base);
-}
-
-static void ppgtt_release(struct kref *kref)
-{
-       struct i915_hw_ppgtt *ppgtt =
-               container_of(kref, struct i915_hw_ppgtt, ref);
-
-       do_ppgtt_cleanup(ppgtt);
-       kfree(ppgtt);
-}
-
 static size_t get_context_alignment(struct drm_device *dev)
 {
        if (IS_GEN6(dev))
@@ -179,24 +135,20 @@ static int get_context_size(struct drm_device *dev)
 void i915_gem_context_free(struct kref *ctx_ref)
 {
        struct intel_context *ctx = container_of(ctx_ref,
-                                                  typeof(*ctx), ref);
-       struct i915_hw_ppgtt *ppgtt = NULL;
+                                                typeof(*ctx), ref);
 
-       if (ctx->legacy_hw_ctx.rcs_state) {
-               /* We refcount even the aliasing PPGTT to keep the code symmetric */
-               if (USES_PPGTT(ctx->legacy_hw_ctx.rcs_state->base.dev))
-                       ppgtt = ctx_to_ppgtt(ctx);
-       }
+       if (i915.enable_execlists)
+               intel_lr_context_free(ctx);
+
+       i915_ppgtt_put(ctx->ppgtt);
 
-       if (ppgtt)
-               kref_put(&ppgtt->ref, ppgtt_release);
        if (ctx->legacy_hw_ctx.rcs_state)
                drm_gem_object_unreference(&ctx->legacy_hw_ctx.rcs_state->base);
        list_del(&ctx->link);
        kfree(ctx);
 }
 
-static struct drm_i915_gem_object *
+struct drm_i915_gem_object *
 i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
 {
        struct drm_i915_gem_object *obj;
@@ -226,29 +178,9 @@ i915_gem_alloc_context_obj(struct drm_device *dev, size_t size)
        return obj;
 }
 
-static struct i915_hw_ppgtt *
-create_vm_for_ctx(struct drm_device *dev, struct intel_context *ctx)
-{
-       struct i915_hw_ppgtt *ppgtt;
-       int ret;
-
-       ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
-       if (!ppgtt)
-               return ERR_PTR(-ENOMEM);
-
-       ret = i915_gem_init_ppgtt(dev, ppgtt);
-       if (ret) {
-               kfree(ppgtt);
-               return ERR_PTR(ret);
-       }
-
-       ppgtt->ctx = ctx;
-       return ppgtt;
-}
-
 static struct intel_context *
 __create_hw_context(struct drm_device *dev,
-                 struct drm_i915_file_private *file_priv)
+                   struct drm_i915_file_private *file_priv)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_context *ctx;
@@ -301,11 +233,9 @@ err_out:
  */
 static struct intel_context *
 i915_gem_create_context(struct drm_device *dev,
-                       struct drm_i915_file_private *file_priv,
-                       bool create_vm)
+                       struct drm_i915_file_private *file_priv)
 {
        const bool is_global_default_ctx = file_priv == NULL;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_context *ctx;
        int ret = 0;
 
@@ -331,34 +261,18 @@ i915_gem_create_context(struct drm_device *dev,
                }
        }
 
-       if (create_vm) {
-               struct i915_hw_ppgtt *ppgtt = create_vm_for_ctx(dev, ctx);
+       if (USES_FULL_PPGTT(dev)) {
+               struct i915_hw_ppgtt *ppgtt = i915_ppgtt_create(dev, file_priv);
 
                if (IS_ERR_OR_NULL(ppgtt)) {
                        DRM_DEBUG_DRIVER("PPGTT setup failed (%ld)\n",
                                         PTR_ERR(ppgtt));
                        ret = PTR_ERR(ppgtt);
                        goto err_unpin;
-               } else
-                       ctx->vm = &ppgtt->base;
-
-               /* This case is reserved for the global default context and
-                * should only happen once. */
-               if (is_global_default_ctx) {
-                       if (WARN_ON(dev_priv->mm.aliasing_ppgtt)) {
-                               ret = -EEXIST;
-                               goto err_unpin;
-                       }
-
-                       dev_priv->mm.aliasing_ppgtt = ppgtt;
                }
-       } else if (USES_PPGTT(dev)) {
-               /* For platforms which only have aliasing PPGTT, we fake the
-                * address space and refcounting. */
-               ctx->vm = &dev_priv->mm.aliasing_ppgtt->base;
-               kref_get(&dev_priv->mm.aliasing_ppgtt->ref);
-       } else
-               ctx->vm = &dev_priv->gtt.base;
+
+               ctx->ppgtt = ppgtt;
+       }
 
        return ctx;
 
@@ -417,7 +331,11 @@ int i915_gem_context_init(struct drm_device *dev)
        if (WARN_ON(dev_priv->ring[RCS].default_context))
                return 0;
 
-       if (HAS_HW_CONTEXTS(dev)) {
+       if (i915.enable_execlists) {
+               /* NB: intentionally left blank. We will allocate our own
+                * backing objects as we need them, thank you very much */
+               dev_priv->hw_context_size = 0;
+       } else if (HAS_HW_CONTEXTS(dev)) {
                dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
                if (dev_priv->hw_context_size > (1<<20)) {
                        DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size %d\n",
@@ -426,18 +344,23 @@ int i915_gem_context_init(struct drm_device *dev)
                }
        }
 
-       ctx = i915_gem_create_context(dev, NULL, USES_PPGTT(dev));
+       ctx = i915_gem_create_context(dev, NULL);
        if (IS_ERR(ctx)) {
                DRM_ERROR("Failed to create default global context (error %ld)\n",
                          PTR_ERR(ctx));
                return PTR_ERR(ctx);
        }
 
-       /* NB: RCS will hold a ref for all rings */
-       for (i = 0; i < I915_NUM_RINGS; i++)
-               dev_priv->ring[i].default_context = ctx;
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct intel_engine_cs *ring = &dev_priv->ring[i];
 
-       DRM_DEBUG_DRIVER("%s context support initialized\n", dev_priv->hw_context_size ? "HW" : "fake");
+               /* NB: RCS will hold a ref for all rings */
+               ring->default_context = ctx;
+       }
+
+       DRM_DEBUG_DRIVER("%s context support initialized\n",
+                       i915.enable_execlists ? "LR" :
+                       dev_priv->hw_context_size ? "HW" : "fake");
        return 0;
 }
 
@@ -489,13 +412,6 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
        struct intel_engine_cs *ring;
        int ret, i;
 
-       /* This is the only place the aliasing PPGTT gets enabled, which means
-        * it has to happen before we bail on reset */
-       if (dev_priv->mm.aliasing_ppgtt) {
-               struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
-               ppgtt->enable(ppgtt);
-       }
-
        /* FIXME: We should make this work, even in reset */
        if (i915_reset_in_progress(&dev_priv->gpu_error))
                return 0;
@@ -527,7 +443,7 @@ int i915_gem_context_open(struct drm_device *dev, struct drm_file *file)
        idr_init(&file_priv->context_idr);
 
        mutex_lock(&dev->struct_mutex);
-       ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
+       ctx = i915_gem_create_context(dev, file_priv);
        mutex_unlock(&dev->struct_mutex);
 
        if (IS_ERR(ctx)) {
@@ -614,7 +530,6 @@ static int do_switch(struct intel_engine_cs *ring,
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct intel_context *from = ring->last_context;
-       struct i915_hw_ppgtt *ppgtt = ctx_to_ppgtt(to);
        u32 hw_flags = 0;
        bool uninitialized = false;
        int ret, i;
@@ -642,8 +557,8 @@ static int do_switch(struct intel_engine_cs *ring,
         */
        from = ring->last_context;
 
-       if (USES_FULL_PPGTT(ring->dev)) {
-               ret = ppgtt->switch_mm(ppgtt, ring, false);
+       if (to->ppgtt) {
+               ret = to->ppgtt->switch_mm(to->ppgtt, ring, false);
                if (ret)
                        goto unpin_out;
        }
@@ -766,9 +681,9 @@ int i915_switch_context(struct intel_engine_cs *ring,
        return do_switch(ring, to);
 }
 
-static bool hw_context_enabled(struct drm_device *dev)
+static bool contexts_enabled(struct drm_device *dev)
 {
-       return to_i915(dev)->hw_context_size;
+       return i915.enable_execlists || to_i915(dev)->hw_context_size;
 }
 
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
@@ -779,14 +694,14 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
        struct intel_context *ctx;
        int ret;
 
-       if (!hw_context_enabled(dev))
+       if (!contexts_enabled(dev))
                return -ENODEV;
 
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                return ret;
 
-       ctx = i915_gem_create_context(dev, file_priv, USES_FULL_PPGTT(dev));
+       ctx = i915_gem_create_context(dev, file_priv);
        mutex_unlock(&dev->struct_mutex);
        if (IS_ERR(ctx))
                return PTR_ERR(ctx);
index 60998fc4e5b22147687db554a4c80f27d08e1bea..1a0611bb576b3eb9b78ede149955f36b798360df 100644 (file)
@@ -35,6 +35,7 @@
 
 #define  __EXEC_OBJECT_HAS_PIN (1<<31)
 #define  __EXEC_OBJECT_HAS_FENCE (1<<30)
+#define  __EXEC_OBJECT_NEEDS_MAP (1<<29)
 #define  __EXEC_OBJECT_NEEDS_BIAS (1<<28)
 
 #define BATCH_OFFSET_BIAS (256*1024)
@@ -94,7 +95,6 @@ eb_lookup_vmas(struct eb_vmas *eb,
               struct i915_address_space *vm,
               struct drm_file *file)
 {
-       struct drm_i915_private *dev_priv = vm->dev->dev_private;
        struct drm_i915_gem_object *obj;
        struct list_head objects;
        int i, ret;
@@ -129,20 +129,6 @@ eb_lookup_vmas(struct eb_vmas *eb,
        i = 0;
        while (!list_empty(&objects)) {
                struct i915_vma *vma;
-               struct i915_address_space *bind_vm = vm;
-
-               if (exec[i].flags & EXEC_OBJECT_NEEDS_GTT &&
-                   USES_FULL_PPGTT(vm->dev)) {
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               /* If we have secure dispatch, or the userspace assures us that
-                * they know what they're doing, use the GGTT VM.
-                */
-               if (((args->flags & I915_EXEC_SECURE) &&
-                   (i == (args->buffer_count - 1))))
-                       bind_vm = &dev_priv->gtt.base;
 
                obj = list_first_entry(&objects,
                                       struct drm_i915_gem_object,
@@ -156,7 +142,7 @@ eb_lookup_vmas(struct eb_vmas *eb,
                 * from the (obj, vm) we don't run the risk of creating
                 * duplicated vmas for the same vm.
                 */
-               vma = i915_gem_obj_lookup_or_create_vma(obj, bind_vm);
+               vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
                if (IS_ERR(vma)) {
                        DRM_DEBUG("Failed to lookup VMA\n");
                        ret = PTR_ERR(vma);
@@ -307,7 +293,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
        struct drm_device *dev = obj->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint64_t delta = reloc->delta + target_offset;
-       uint32_t __iomem *reloc_entry;
+       uint64_t offset;
        void __iomem *reloc_page;
        int ret;
 
@@ -320,25 +306,24 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
                return ret;
 
        /* Map the page containing the relocation we're going to perform.  */
-       reloc->offset += i915_gem_obj_ggtt_offset(obj);
+       offset = i915_gem_obj_ggtt_offset(obj);
+       offset += reloc->offset;
        reloc_page = io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
-                       reloc->offset & PAGE_MASK);
-       reloc_entry = (uint32_t __iomem *)
-               (reloc_page + offset_in_page(reloc->offset));
-       iowrite32(lower_32_bits(delta), reloc_entry);
+                                             offset & PAGE_MASK);
+       iowrite32(lower_32_bits(delta), reloc_page + offset_in_page(offset));
 
        if (INTEL_INFO(dev)->gen >= 8) {
-               reloc_entry += 1;
+               offset += sizeof(uint32_t);
 
-               if (offset_in_page(reloc->offset + sizeof(uint32_t)) == 0) {
+               if (offset_in_page(offset) == 0) {
                        io_mapping_unmap_atomic(reloc_page);
-                       reloc_page = io_mapping_map_atomic_wc(
-                                       dev_priv->gtt.mappable,
-                                       reloc->offset + sizeof(uint32_t));
-                       reloc_entry = reloc_page;
+                       reloc_page =
+                               io_mapping_map_atomic_wc(dev_priv->gtt.mappable,
+                                                        offset);
                }
 
-               iowrite32(upper_32_bits(delta), reloc_entry);
+               iowrite32(upper_32_bits(delta),
+                         reloc_page + offset_in_page(offset));
        }
 
        io_mapping_unmap_atomic(reloc_page);
@@ -534,14 +519,6 @@ i915_gem_execbuffer_relocate(struct eb_vmas *eb)
        return ret;
 }
 
-static int
-need_reloc_mappable(struct i915_vma *vma)
-{
-       struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
-       return entry->relocation_count && !use_cpu_reloc(vma->obj) &&
-               i915_is_ggtt(vma->vm);
-}
-
 static int
 i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
                                struct intel_engine_cs *ring,
@@ -549,20 +526,12 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
 {
        struct drm_i915_gem_object *obj = vma->obj;
        struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
-       bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
-       bool need_fence;
        uint64_t flags;
        int ret;
 
        flags = 0;
-
-       need_fence =
-               has_fenced_gpu_access &&
-               entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
-               obj->tiling_mode != I915_TILING_NONE;
-       if (need_fence || need_reloc_mappable(vma))
+       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP)
                flags |= PIN_MAPPABLE;
-
        if (entry->flags & EXEC_OBJECT_NEEDS_GTT)
                flags |= PIN_GLOBAL;
        if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS)
@@ -574,17 +543,13 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
 
        entry->flags |= __EXEC_OBJECT_HAS_PIN;
 
-       if (has_fenced_gpu_access) {
-               if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
-                       ret = i915_gem_object_get_fence(obj);
-                       if (ret)
-                               return ret;
-
-                       if (i915_gem_object_pin_fence(obj))
-                               entry->flags |= __EXEC_OBJECT_HAS_FENCE;
+       if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
+               ret = i915_gem_object_get_fence(obj);
+               if (ret)
+                       return ret;
 
-                       obj->pending_fenced_gpu_access = true;
-               }
+               if (i915_gem_object_pin_fence(obj))
+                       entry->flags |= __EXEC_OBJECT_HAS_FENCE;
        }
 
        if (entry->offset != vma->node.start) {
@@ -601,26 +566,40 @@ i915_gem_execbuffer_reserve_vma(struct i915_vma *vma,
 }
 
 static bool
-eb_vma_misplaced(struct i915_vma *vma, bool has_fenced_gpu_access)
+need_reloc_mappable(struct i915_vma *vma)
 {
        struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
-       struct drm_i915_gem_object *obj = vma->obj;
-       bool need_fence, need_mappable;
 
-       need_fence =
-               has_fenced_gpu_access &&
-               entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
-               obj->tiling_mode != I915_TILING_NONE;
-       need_mappable = need_fence || need_reloc_mappable(vma);
+       if (entry->relocation_count == 0)
+               return false;
+
+       if (!i915_is_ggtt(vma->vm))
+               return false;
+
+       /* See also use_cpu_reloc() */
+       if (HAS_LLC(vma->obj->base.dev))
+               return false;
 
-       WARN_ON((need_mappable || need_fence) &&
+       if (vma->obj->base.write_domain == I915_GEM_DOMAIN_CPU)
+               return false;
+
+       return true;
+}
+
+static bool
+eb_vma_misplaced(struct i915_vma *vma)
+{
+       struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
+       struct drm_i915_gem_object *obj = vma->obj;
+
+       WARN_ON(entry->flags & __EXEC_OBJECT_NEEDS_MAP &&
               !i915_is_ggtt(vma->vm));
 
        if (entry->alignment &&
            vma->node.start & (entry->alignment - 1))
                return true;
 
-       if (need_mappable && !obj->map_and_fenceable)
+       if (entry->flags & __EXEC_OBJECT_NEEDS_MAP && !obj->map_and_fenceable)
                return true;
 
        if (entry->flags & __EXEC_OBJECT_NEEDS_BIAS &&
@@ -642,9 +621,6 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
        bool has_fenced_gpu_access = INTEL_INFO(ring->dev)->gen < 4;
        int retry;
 
-       if (list_empty(vmas))
-               return 0;
-
        i915_gem_retire_requests_ring(ring);
 
        vm = list_first_entry(vmas, struct i915_vma, exec_list)->vm;
@@ -658,20 +634,21 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
                obj = vma->obj;
                entry = vma->exec_entry;
 
+               if (!has_fenced_gpu_access)
+                       entry->flags &= ~EXEC_OBJECT_NEEDS_FENCE;
                need_fence =
-                       has_fenced_gpu_access &&
                        entry->flags & EXEC_OBJECT_NEEDS_FENCE &&
                        obj->tiling_mode != I915_TILING_NONE;
                need_mappable = need_fence || need_reloc_mappable(vma);
 
-               if (need_mappable)
+               if (need_mappable) {
+                       entry->flags |= __EXEC_OBJECT_NEEDS_MAP;
                        list_move(&vma->exec_list, &ordered_vmas);
-               else
+               else
                        list_move_tail(&vma->exec_list, &ordered_vmas);
 
                obj->base.pending_read_domains = I915_GEM_GPU_DOMAINS & ~I915_GEM_DOMAIN_COMMAND;
                obj->base.pending_write_domain = 0;
-               obj->pending_fenced_gpu_access = false;
        }
        list_splice(&ordered_vmas, vmas);
 
@@ -696,7 +673,7 @@ i915_gem_execbuffer_reserve(struct intel_engine_cs *ring,
                        if (!drm_mm_node_allocated(&vma->node))
                                continue;
 
-                       if (eb_vma_misplaced(vma, has_fenced_gpu_access))
+                       if (eb_vma_misplaced(vma))
                                ret = i915_vma_unbind(vma);
                        else
                                ret = i915_gem_execbuffer_reserve_vma(vma, ring, need_relocs);
@@ -744,9 +721,6 @@ i915_gem_execbuffer_relocate_slow(struct drm_device *dev,
        int i, total, ret;
        unsigned count = args->buffer_count;
 
-       if (WARN_ON(list_empty(&eb->vmas)))
-               return 0;
-
        vm = list_first_entry(&eb->vmas, struct i915_vma, exec_list)->vm;
 
        /* We may process another execbuffer during the unlock... */
@@ -890,18 +864,24 @@ i915_gem_check_execbuffer(struct drm_i915_gem_execbuffer2 *exec)
 }
 
 static int
-validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
+validate_exec_list(struct drm_device *dev,
+                  struct drm_i915_gem_exec_object2 *exec,
                   int count)
 {
-       int i;
        unsigned relocs_total = 0;
        unsigned relocs_max = UINT_MAX / sizeof(struct drm_i915_gem_relocation_entry);
+       unsigned invalid_flags;
+       int i;
+
+       invalid_flags = __EXEC_OBJECT_UNKNOWN_FLAGS;
+       if (USES_FULL_PPGTT(dev))
+               invalid_flags |= EXEC_OBJECT_NEEDS_GTT;
 
        for (i = 0; i < count; i++) {
                char __user *ptr = to_user_ptr(exec[i].relocs_ptr);
                int length; /* limited by fault_in_pages_readable() */
 
-               if (exec[i].flags & __EXEC_OBJECT_UNKNOWN_FLAGS)
+               if (exec[i].flags & invalid_flags)
                        return -EINVAL;
 
                /* First check for malicious input causing overflow in
@@ -951,16 +931,26 @@ i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
                return ERR_PTR(-EIO);
        }
 
+       if (i915.enable_execlists && !ctx->engine[ring->id].state) {
+               int ret = intel_lr_context_deferred_create(ctx, ring);
+               if (ret) {
+                       DRM_DEBUG("Could not create LRC %u: %d\n", ctx_id, ret);
+                       return ERR_PTR(ret);
+               }
+       }
+
        return ctx;
 }
 
-static void
+void
 i915_gem_execbuffer_move_to_active(struct list_head *vmas,
                                   struct intel_engine_cs *ring)
 {
+       u32 seqno = intel_ring_get_seqno(ring);
        struct i915_vma *vma;
 
        list_for_each_entry(vma, vmas, exec_list) {
+               struct drm_i915_gem_exec_object2 *entry = vma->exec_entry;
                struct drm_i915_gem_object *obj = vma->obj;
                u32 old_read = obj->base.read_domains;
                u32 old_write = obj->base.write_domain;
@@ -969,24 +959,31 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
                if (obj->base.write_domain == 0)
                        obj->base.pending_read_domains |= obj->base.read_domains;
                obj->base.read_domains = obj->base.pending_read_domains;
-               obj->fenced_gpu_access = obj->pending_fenced_gpu_access;
 
                i915_vma_move_to_active(vma, ring);
                if (obj->base.write_domain) {
                        obj->dirty = 1;
-                       obj->last_write_seqno = intel_ring_get_seqno(ring);
+                       obj->last_write_seqno = seqno;
 
                        intel_fb_obj_invalidate(obj, ring);
 
                        /* update for the implicit flush after a batch */
                        obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
                }
+               if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
+                       obj->last_fenced_seqno = seqno;
+                       if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
+                               struct drm_i915_private *dev_priv = to_i915(ring->dev);
+                               list_move_tail(&dev_priv->fence_regs[obj->fence_reg].lru_list,
+                                              &dev_priv->mm.fence_list);
+                       }
+               }
 
                trace_i915_gem_object_change_domain(obj, old_read, old_write);
        }
 }
 
-static void
+void
 i915_gem_execbuffer_retire_commands(struct drm_device *dev,
                                    struct drm_file *file,
                                    struct intel_engine_cs *ring,
@@ -1026,14 +1023,14 @@ i915_reset_gen7_sol_offsets(struct drm_device *dev,
        return 0;
 }
 
-static int
-legacy_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
-                            struct intel_engine_cs *ring,
-                            struct intel_context *ctx,
-                            struct drm_i915_gem_execbuffer2 *args,
-                            struct list_head *vmas,
-                            struct drm_i915_gem_object *batch_obj,
-                            u64 exec_start, u32 flags)
+int
+i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
+                              struct intel_engine_cs *ring,
+                              struct intel_context *ctx,
+                              struct drm_i915_gem_execbuffer2 *args,
+                              struct list_head *vmas,
+                              struct drm_i915_gem_object *batch_obj,
+                              u64 exec_start, u32 flags)
 {
        struct drm_clip_rect *cliprects = NULL;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1254,7 +1251,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        if (!i915_gem_check_execbuffer(args))
                return -EINVAL;
 
-       ret = validate_exec_list(exec, args->buffer_count);
+       ret = validate_exec_list(dev, exec, args->buffer_count);
        if (ret)
                return ret;
 
@@ -1318,8 +1315,9 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
        i915_gem_context_reference(ctx);
 
-       vm = ctx->vm;
-       if (!USES_FULL_PPGTT(dev))
+       if (ctx->ppgtt)
+               vm = &ctx->ppgtt->base;
+       else
                vm = &dev_priv->gtt.base;
 
        eb = eb_create(args);
@@ -1386,25 +1384,36 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        /* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
         * batch" bit. Hence we need to pin secure batches into the global gtt.
         * hsw should have this fixed, but bdw mucks it up again. */
-       if (flags & I915_DISPATCH_SECURE &&
-           !batch_obj->has_global_gtt_mapping) {
-               /* When we have multiple VMs, we'll need to make sure that we
-                * allocate space first */
-               struct i915_vma *vma = i915_gem_obj_to_ggtt(batch_obj);
-               BUG_ON(!vma);
-               vma->bind_vma(vma, batch_obj->cache_level, GLOBAL_BIND);
-       }
+       if (flags & I915_DISPATCH_SECURE) {
+               /*
+                * So on first glance it looks freaky that we pin the batch here
+                * outside of the reservation loop. But:
+                * - The batch is already pinned into the relevant ppgtt, so we
+                *   already have the backing storage fully allocated.
+                * - No other BO uses the global gtt (well contexts, but meh),
+                *   so we don't really have issues with mutliple objects not
+                *   fitting due to fragmentation.
+                * So this is actually safe.
+                */
+               ret = i915_gem_obj_ggtt_pin(batch_obj, 0, 0);
+               if (ret)
+                       goto err;
 
-       if (flags & I915_DISPATCH_SECURE)
                exec_start += i915_gem_obj_ggtt_offset(batch_obj);
-       else
+       else
                exec_start += i915_gem_obj_offset(batch_obj, vm);
 
-       ret = legacy_ringbuffer_submission(dev, file, ring, ctx,
-                       args, &eb->vmas, batch_obj, exec_start, flags);
-       if (ret)
-               goto err;
+       ret = dev_priv->gt.do_execbuf(dev, file, ring, ctx, args,
+                                     &eb->vmas, batch_obj, exec_start, flags);
 
+       /*
+        * FIXME: We crucially rely upon the active tracking for the (ppgtt)
+        * batch vma for correctness. For less ugly and less fragility this
+        * needs to be adjusted to also track the ggtt batch vma properly as
+        * active.
+        */
+       if (flags & I915_DISPATCH_SECURE)
+               i915_gem_object_ggtt_unpin(batch_obj);
 err:
        /* the request owns the ref now */
        i915_gem_context_unreference(ctx);
index b4b7cfd226b7dd782a9a1270c9cc3313bedbe379..4db237065610e9b6800e96fe57560ef1f6067c12 100644 (file)
@@ -67,7 +67,6 @@ static void ppgtt_bind_vma(struct i915_vma *vma,
                           enum i915_cache_level cache_level,
                           u32 flags);
 static void ppgtt_unbind_vma(struct i915_vma *vma);
-static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt);
 
 static inline gen8_gtt_pte_t gen8_pte_encode(dma_addr_t addr,
                                             enum i915_cache_level level,
@@ -392,9 +391,6 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
 
-       list_del(&vm->global_link);
-       drm_mm_takedown(&vm->mm);
-
        gen8_ppgtt_unmap_pages(ppgtt);
        gen8_ppgtt_free(ppgtt);
 }
@@ -604,7 +600,6 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
                kunmap_atomic(pd_vaddr);
        }
 
-       ppgtt->enable = gen8_ppgtt_enable;
        ppgtt->switch_mm = gen8_mm_switch;
        ppgtt->base.clear_range = gen8_ppgtt_clear_range;
        ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
@@ -825,39 +820,26 @@ static int gen6_mm_switch(struct i915_hw_ppgtt *ppgtt,
        return 0;
 }
 
-static int gen8_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+static void gen8_ppgtt_enable(struct drm_device *dev)
 {
-       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_engine_cs *ring;
-       int j, ret;
+       int j;
+
+       /* In the case of execlists, PPGTT is enabled by the context descriptor
+        * and the PDPs are contained within the context itself.  We don't
+        * need to do anything here. */
+       if (i915.enable_execlists)
+               return;
 
        for_each_ring(ring, dev_priv, j) {
                I915_WRITE(RING_MODE_GEN7(ring),
                           _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-               /* We promise to do a switch later with FULL PPGTT. If this is
-                * aliasing, this is the one and only switch we'll do */
-               if (USES_FULL_PPGTT(dev))
-                       continue;
-
-               ret = ppgtt->switch_mm(ppgtt, ring, true);
-               if (ret)
-                       goto err_out;
        }
-
-       return 0;
-
-err_out:
-       for_each_ring(ring, dev_priv, j)
-               I915_WRITE(RING_MODE_GEN7(ring),
-                          _MASKED_BIT_DISABLE(GFX_PPGTT_ENABLE));
-       return ret;
 }
 
-static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+static void gen7_ppgtt_enable(struct drm_device *dev)
 {
-       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_engine_cs *ring;
        uint32_t ecochk, ecobits;
@@ -876,31 +858,16 @@ static int gen7_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
        I915_WRITE(GAM_ECOCHK, ecochk);
 
        for_each_ring(ring, dev_priv, i) {
-               int ret;
                /* GFX_MODE is per-ring on gen7+ */
                I915_WRITE(RING_MODE_GEN7(ring),
                           _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-               /* We promise to do a switch later with FULL PPGTT. If this is
-                * aliasing, this is the one and only switch we'll do */
-               if (USES_FULL_PPGTT(dev))
-                       continue;
-
-               ret = ppgtt->switch_mm(ppgtt, ring, true);
-               if (ret)
-                       return ret;
        }
-
-       return 0;
 }
 
-static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
+static void gen6_ppgtt_enable(struct drm_device *dev)
 {
-       struct drm_device *dev = ppgtt->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_engine_cs *ring;
        uint32_t ecochk, gab_ctl, ecobits;
-       int i;
 
        ecobits = I915_READ(GAC_ECO_BITS);
        I915_WRITE(GAC_ECO_BITS, ecobits | ECOBITS_SNB_BIT |
@@ -913,14 +880,6 @@ static int gen6_ppgtt_enable(struct i915_hw_ppgtt *ppgtt)
        I915_WRITE(GAM_ECOCHK, ecochk | ECOCHK_SNB_BIT | ECOCHK_PPGTT_CACHE64B);
 
        I915_WRITE(GFX_MODE, _MASKED_BIT_ENABLE(GFX_PPGTT_ENABLE));
-
-       for_each_ring(ring, dev_priv, i) {
-               int ret = ppgtt->switch_mm(ppgtt, ring, true);
-               if (ret)
-                       return ret;
-       }
-
-       return 0;
 }
 
 /* PPGTT support for Sandybdrige/Gen6 and later */
@@ -1018,8 +977,6 @@ static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
        struct i915_hw_ppgtt *ppgtt =
                container_of(vm, struct i915_hw_ppgtt, base);
 
-       list_del(&vm->global_link);
-       drm_mm_takedown(&ppgtt->base.mm);
        drm_mm_remove_node(&ppgtt->node);
 
        gen6_ppgtt_unmap_pages(ppgtt);
@@ -1140,13 +1097,10 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
 
        ppgtt->base.pte_encode = dev_priv->gtt.base.pte_encode;
        if (IS_GEN6(dev)) {
-               ppgtt->enable = gen6_ppgtt_enable;
                ppgtt->switch_mm = gen6_mm_switch;
        } else if (IS_HASWELL(dev)) {
-               ppgtt->enable = gen7_ppgtt_enable;
                ppgtt->switch_mm = hsw_mm_switch;
        } else if (IS_GEN7(dev)) {
-               ppgtt->enable = gen7_ppgtt_enable;
                ppgtt->switch_mm = gen7_mm_switch;
        } else
                BUG();
@@ -1177,39 +1131,108 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
                         ppgtt->node.size >> 20,
                         ppgtt->node.start / PAGE_SIZE);
 
+       gen6_write_pdes(ppgtt);
+       DRM_DEBUG("Adding PPGTT at offset %x\n",
+                 ppgtt->pd_offset << 10);
+
        return 0;
 }
 
-int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int ret = 0;
 
        ppgtt->base.dev = dev;
        ppgtt->base.scratch = dev_priv->gtt.base.scratch;
 
        if (INTEL_INFO(dev)->gen < 8)
-               ret = gen6_ppgtt_init(ppgtt);
+               return gen6_ppgtt_init(ppgtt);
        else if (IS_GEN8(dev))
-               ret = gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
+               return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
        else
                BUG();
+}
+int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
 
-       if (!ret) {
-               struct drm_i915_private *dev_priv = dev->dev_private;
+       ret = __hw_ppgtt_init(dev, ppgtt);
+       if (ret == 0) {
                kref_init(&ppgtt->ref);
                drm_mm_init(&ppgtt->base.mm, ppgtt->base.start,
                            ppgtt->base.total);
                i915_init_vm(dev_priv, &ppgtt->base);
-               if (INTEL_INFO(dev)->gen < 8) {
-                       gen6_write_pdes(ppgtt);
-                       DRM_DEBUG("Adding PPGTT at offset %x\n",
-                                 ppgtt->pd_offset << 10);
+       }
+
+       return ret;
+}
+
+int i915_ppgtt_init_hw(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring;
+       struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+       int i, ret = 0;
+
+       if (!USES_PPGTT(dev))
+               return 0;
+
+       if (IS_GEN6(dev))
+               gen6_ppgtt_enable(dev);
+       else if (IS_GEN7(dev))
+               gen7_ppgtt_enable(dev);
+       else if (INTEL_INFO(dev)->gen >= 8)
+               gen8_ppgtt_enable(dev);
+       else
+               WARN_ON(1);
+
+       if (ppgtt) {
+               for_each_ring(ring, dev_priv, i) {
+                       ret = ppgtt->switch_mm(ppgtt, ring, true);
+                       if (ret != 0)
+                               return ret;
                }
        }
 
        return ret;
 }
+struct i915_hw_ppgtt *
+i915_ppgtt_create(struct drm_device *dev, struct drm_i915_file_private *fpriv)
+{
+       struct i915_hw_ppgtt *ppgtt;
+       int ret;
+
+       ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+       if (!ppgtt)
+               return ERR_PTR(-ENOMEM);
+
+       ret = i915_ppgtt_init(dev, ppgtt);
+       if (ret) {
+               kfree(ppgtt);
+               return ERR_PTR(ret);
+       }
+
+       ppgtt->file_priv = fpriv;
+
+       return ppgtt;
+}
+
+void  i915_ppgtt_release(struct kref *kref)
+{
+       struct i915_hw_ppgtt *ppgtt =
+               container_of(kref, struct i915_hw_ppgtt, ref);
+
+       /* vmas should already be unbound */
+       WARN_ON(!list_empty(&ppgtt->base.active_list));
+       WARN_ON(!list_empty(&ppgtt->base.inactive_list));
+
+       list_del(&ppgtt->base.global_link);
+       drm_mm_takedown(&ppgtt->base.mm);
+
+       ppgtt->base.cleanup(&ppgtt->base);
+       kfree(ppgtt);
+}
 
 static void
 ppgtt_bind_vma(struct i915_vma *vma,
@@ -1664,10 +1687,10 @@ static void i915_gtt_color_adjust(struct drm_mm_node *node,
        }
 }
 
-void i915_gem_setup_global_gtt(struct drm_device *dev,
-                              unsigned long start,
-                              unsigned long mappable_end,
-                              unsigned long end)
+int i915_gem_setup_global_gtt(struct drm_device *dev,
+                             unsigned long start,
+                             unsigned long mappable_end,
+                             unsigned long end)
 {
        /* Let GEM Manage all of the aperture.
         *
@@ -1683,6 +1706,7 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
        struct drm_mm_node *entry;
        struct drm_i915_gem_object *obj;
        unsigned long hole_start, hole_end;
+       int ret;
 
        BUG_ON(mappable_end > end);
 
@@ -1694,14 +1718,16 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
        /* Mark any preallocated objects as occupied */
        list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
                struct i915_vma *vma = i915_gem_obj_to_vma(obj, ggtt_vm);
-               int ret;
+
                DRM_DEBUG_KMS("reserving preallocated space: %lx + %zx\n",
                              i915_gem_obj_ggtt_offset(obj), obj->base.size);
 
                WARN_ON(i915_gem_obj_ggtt_bound(obj));
                ret = drm_mm_reserve_node(&ggtt_vm->mm, &vma->node);
-               if (ret)
-                       DRM_DEBUG_KMS("Reservation failed\n");
+               if (ret) {
+                       DRM_DEBUG_KMS("Reservation failed: %i\n", ret);
+                       return ret;
+               }
                obj->has_global_gtt_mapping = 1;
        }
 
@@ -1718,6 +1744,22 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
 
        /* And finally clear the reserved guard page */
        ggtt_vm->clear_range(ggtt_vm, end - PAGE_SIZE, PAGE_SIZE, true);
+
+       if (USES_PPGTT(dev) && !USES_FULL_PPGTT(dev)) {
+               struct i915_hw_ppgtt *ppgtt;
+
+               ppgtt = kzalloc(sizeof(*ppgtt), GFP_KERNEL);
+               if (!ppgtt)
+                       return -ENOMEM;
+
+               ret = __hw_ppgtt_init(dev, ppgtt);
+               if (ret != 0)
+                       return ret;
+
+               dev_priv->mm.aliasing_ppgtt = ppgtt;
+       }
+
+       return 0;
 }
 
 void i915_gem_init_global_gtt(struct drm_device *dev)
@@ -1731,6 +1773,25 @@ void i915_gem_init_global_gtt(struct drm_device *dev)
        i915_gem_setup_global_gtt(dev, 0, mappable_size, gtt_size);
 }
 
+void i915_global_gtt_cleanup(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_address_space *vm = &dev_priv->gtt.base;
+
+       if (dev_priv->mm.aliasing_ppgtt) {
+               struct i915_hw_ppgtt *ppgtt = dev_priv->mm.aliasing_ppgtt;
+
+               ppgtt->base.cleanup(&ppgtt->base);
+       }
+
+       if (drm_mm_initialized(&vm->mm)) {
+               drm_mm_takedown(&vm->mm);
+               list_del(&vm->global_link);
+       }
+
+       vm->cleanup(vm);
+}
+
 static int setup_scratch_page(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1999,10 +2060,6 @@ static void gen6_gmch_remove(struct i915_address_space *vm)
 
        struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base);
 
-       if (drm_mm_initialized(&vm->mm)) {
-               drm_mm_takedown(&vm->mm);
-               list_del(&vm->global_link);
-       }
        iounmap(gtt->gsm);
        teardown_scratch_page(vm->dev);
 }
@@ -2035,10 +2092,6 @@ static int i915_gmch_probe(struct drm_device *dev,
 
 static void i915_gmch_remove(struct i915_address_space *vm)
 {
-       if (drm_mm_initialized(&vm->mm)) {
-               drm_mm_takedown(&vm->mm);
-               list_del(&vm->global_link);
-       }
        intel_gmch_remove();
 }
 
@@ -2153,5 +2206,8 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
        if (!vma)
                vma = __i915_gem_vma_create(obj, vm);
 
+       if (!i915_is_ggtt(vm))
+               i915_ppgtt_get(i915_vm_to_ppgtt(vm));
+
        return vma;
 }
index 666c938a51e37329cb0a2e1bd25a6c21b7b6d38e..6280648d4805bd5216f45dfcc9e4be238967c75a 100644 (file)
@@ -34,6 +34,8 @@
 #ifndef __I915_GEM_GTT_H__
 #define __I915_GEM_GTT_H__
 
+struct drm_i915_file_private;
+
 typedef uint32_t gen6_gtt_pte_t;
 typedef uint64_t gen8_gtt_pte_t;
 typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
@@ -258,7 +260,7 @@ struct i915_hw_ppgtt {
                dma_addr_t *gen8_pt_dma_addr[4];
        };
 
-       struct intel_context *ctx;
+       struct drm_i915_file_private *file_priv;
 
        int (*enable)(struct i915_hw_ppgtt *ppgtt);
        int (*switch_mm)(struct i915_hw_ppgtt *ppgtt,
@@ -269,10 +271,26 @@ struct i915_hw_ppgtt {
 
 int i915_gem_gtt_init(struct drm_device *dev);
 void i915_gem_init_global_gtt(struct drm_device *dev);
-void i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
-                              unsigned long mappable_end, unsigned long end);
-
-int i915_gem_init_ppgtt(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt);
+int i915_gem_setup_global_gtt(struct drm_device *dev, unsigned long start,
+                             unsigned long mappable_end, unsigned long end);
+void i915_global_gtt_cleanup(struct drm_device *dev);
+
+
+int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt);
+int i915_ppgtt_init_hw(struct drm_device *dev);
+void i915_ppgtt_release(struct kref *kref);
+struct i915_hw_ppgtt *i915_ppgtt_create(struct drm_device *dev,
+                                       struct drm_i915_file_private *fpriv);
+static inline void i915_ppgtt_get(struct i915_hw_ppgtt *ppgtt)
+{
+       if (ppgtt)
+               kref_get(&ppgtt->ref);
+}
+static inline void i915_ppgtt_put(struct i915_hw_ppgtt *ppgtt)
+{
+       if (ppgtt)
+               kref_put(&ppgtt->ref, i915_ppgtt_release);
+}
 
 void i915_check_and_clear_faults(struct drm_device *dev);
 void i915_gem_suspend_gtt_mappings(struct drm_device *dev);
index cb150e8b433658feaa3ecf6f4d817bc5b495a953..7e623bf097a10751c4abfb6230a19e2648d28185 100644 (file)
@@ -376,7 +376,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
 
                if (ret == 0) {
                        obj->fence_dirty =
-                               obj->fenced_gpu_access ||
+                               obj->last_fenced_seqno ||
                                obj->fence_reg != I915_FENCE_REG_NONE;
 
                        obj->tiling_mode = args->tiling_mode;
index eab41f9390f8c3bd1907c7625488c977a910ead3..35e70d5d62828b0d99bf122fb7e37fff8931ba5b 100644 (file)
@@ -192,10 +192,10 @@ static void print_error_buffers(struct drm_i915_error_state_buf *m,
                                struct drm_i915_error_buffer *err,
                                int count)
 {
-       err_printf(m, "%s [%d]:\n", name, count);
+       err_printf(m, "  %s [%d]:\n", name, count);
 
        while (count--) {
-               err_printf(m, "  %08x %8u %02x %02x %x %x",
+               err_printf(m, "    %08x %8u %02x %02x %x %x",
                           err->gtt_offset,
                           err->size,
                           err->read_domains,
@@ -393,15 +393,17 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                i915_ring_error_state(m, dev, &error->ring[i]);
        }
 
-       if (error->active_bo)
+       for (i = 0; i < error->vm_count; i++) {
+               err_printf(m, "vm[%d]\n", i);
+
                print_error_buffers(m, "Active",
-                                   error->active_bo[0],
-                                   error->active_bo_count[0]);
+                                   error->active_bo[i],
+                                   error->active_bo_count[i]);
 
-       if (error->pinned_bo)
                print_error_buffers(m, "Pinned",
-                                   error->pinned_bo[0],
-                                   error->pinned_bo_count[0]);
+                                   error->pinned_bo[i],
+                                   error->pinned_bo_count[i]);
+       }
 
        for (i = 0; i < ARRAY_SIZE(error->ring); i++) {
                obj = error->ring[i].batchbuffer;
@@ -644,13 +646,15 @@ unwind:
                                       (src)->base.size>>PAGE_SHIFT)
 
 static void capture_bo(struct drm_i915_error_buffer *err,
-                      struct drm_i915_gem_object *obj)
+                      struct i915_vma *vma)
 {
+       struct drm_i915_gem_object *obj = vma->obj;
+
        err->size = obj->base.size;
        err->name = obj->base.name;
        err->rseqno = obj->last_read_seqno;
        err->wseqno = obj->last_write_seqno;
-       err->gtt_offset = i915_gem_obj_ggtt_offset(obj);
+       err->gtt_offset = vma->node.start;
        err->read_domains = obj->base.read_domains;
        err->write_domain = obj->base.write_domain;
        err->fence_reg = obj->fence_reg;
@@ -674,7 +678,7 @@ static u32 capture_active_bo(struct drm_i915_error_buffer *err,
        int i = 0;
 
        list_for_each_entry(vma, head, mm_list) {
-               capture_bo(err++, vma->obj);
+               capture_bo(err++, vma);
                if (++i == count)
                        break;
        }
@@ -683,21 +687,27 @@ static u32 capture_active_bo(struct drm_i915_error_buffer *err,
 }
 
 static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
-                            int count, struct list_head *head)
+                            int count, struct list_head *head,
+                            struct i915_address_space *vm)
 {
        struct drm_i915_gem_object *obj;
-       int i = 0;
+       struct drm_i915_error_buffer * const first = err;
+       struct drm_i915_error_buffer * const last = err + count;
 
        list_for_each_entry(obj, head, global_list) {
-               if (!i915_gem_obj_is_pinned(obj))
-                       continue;
+               struct i915_vma *vma;
 
-               capture_bo(err++, obj);
-               if (++i == count)
+               if (err == last)
                        break;
+
+               list_for_each_entry(vma, &obj->vma_list, vma_link)
+                       if (vma->vm == vm && vma->pin_count > 0) {
+                               capture_bo(err++, vma);
+                               break;
+                       }
        }
 
-       return i;
+       return err - first;
 }
 
 /* Generate a semi-unique error code. The code is not meant to have meaning, The
@@ -967,6 +977,12 @@ static void i915_gem_record_rings(struct drm_device *dev,
 
                request = i915_gem_find_active_request(ring);
                if (request) {
+                       struct i915_address_space *vm;
+
+                       vm = request->ctx && request->ctx->ppgtt ?
+                               &request->ctx->ppgtt->base :
+                               &dev_priv->gtt.base;
+
                        /* We need to copy these to an anonymous buffer
                         * as the simplest method to avoid being overwritten
                         * by userspace.
@@ -974,9 +990,7 @@ static void i915_gem_record_rings(struct drm_device *dev,
                        error->ring[i].batchbuffer =
                                i915_error_object_create(dev_priv,
                                                         request->batch_obj,
-                                                        request->ctx ?
-                                                        request->ctx->vm :
-                                                        &dev_priv->gtt.base);
+                                                        vm);
 
                        if (HAS_BROKEN_CS_TLB(dev_priv->dev) &&
                            ring->scratch.obj)
@@ -1049,9 +1063,14 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
        list_for_each_entry(vma, &vm->active_list, mm_list)
                i++;
        error->active_bo_count[ndx] = i;
-       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list)
-               if (i915_gem_obj_is_pinned(obj))
-                       i++;
+
+       list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
+               list_for_each_entry(vma, &obj->vma_list, vma_link)
+                       if (vma->vm == vm && vma->pin_count > 0) {
+                               i++;
+                               break;
+                       }
+       }
        error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx];
 
        if (i) {
@@ -1070,7 +1089,7 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
                error->pinned_bo_count[ndx] =
                        capture_pinned_bo(pinned_bo,
                                          error->pinned_bo_count[ndx],
-                                         &dev_priv->mm.bound_list);
+                                         &dev_priv->mm.bound_list, vm);
        error->active_bo[ndx] = active_bo;
        error->pinned_bo[ndx] = pinned_bo;
 }
@@ -1091,8 +1110,25 @@ static void i915_gem_capture_buffers(struct drm_i915_private *dev_priv,
        error->pinned_bo_count = kcalloc(cnt, sizeof(*error->pinned_bo_count),
                                         GFP_ATOMIC);
 
-       list_for_each_entry(vm, &dev_priv->vm_list, global_link)
-               i915_gem_capture_vm(dev_priv, error, vm, i++);
+       if (error->active_bo == NULL ||
+           error->pinned_bo == NULL ||
+           error->active_bo_count == NULL ||
+           error->pinned_bo_count == NULL) {
+               kfree(error->active_bo);
+               kfree(error->active_bo_count);
+               kfree(error->pinned_bo);
+               kfree(error->pinned_bo_count);
+
+               error->active_bo = NULL;
+               error->active_bo_count = NULL;
+               error->pinned_bo = NULL;
+               error->pinned_bo_count = NULL;
+       } else {
+               list_for_each_entry(vm, &dev_priv->vm_list, global_link)
+                       i915_gem_capture_vm(dev_priv, error, vm, i++);
+
+               error->vm_count = cnt;
+       }
 }
 
 /* Capture all registers which don't fit into another category. */
index 7ccc900eaf6ba249ab713150b598b4b13b0180e6..8b158f02bd0fecea53a72ef45eb119cad1a256c2 100644 (file)
@@ -1322,10 +1322,10 @@ static u32 vlv_c0_residency(struct drm_i915_private *dev_priv,
  * @dev_priv: DRM device private
  *
  */
-static u32 vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv)
+static int vlv_calc_delay_from_C0_counters(struct drm_i915_private *dev_priv)
 {
        u32 residency_C0_up = 0, residency_C0_down = 0;
-       u8 new_delay, adj;
+       int new_delay, adj;
 
        dev_priv->rps.ei_interrupt_count++;
 
@@ -1627,6 +1627,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                                       struct drm_i915_private *dev_priv,
                                       u32 master_ctl)
 {
+       struct intel_engine_cs *ring;
        u32 rcs, bcs, vcs;
        uint32_t tmp = 0;
        irqreturn_t ret = IRQ_NONE;
@@ -1636,12 +1637,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                if (tmp) {
                        I915_WRITE(GEN8_GT_IIR(0), tmp);
                        ret = IRQ_HANDLED;
+
                        rcs = tmp >> GEN8_RCS_IRQ_SHIFT;
-                       bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
+                       ring = &dev_priv->ring[RCS];
                        if (rcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[RCS]);
+                               notify_ring(dev, ring);
+                       if (rcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
+
+                       bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
+                       ring = &dev_priv->ring[BCS];
                        if (bcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[BCS]);
+                               notify_ring(dev, ring);
+                       if (bcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT0)!\n");
        }
@@ -1651,12 +1660,20 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                if (tmp) {
                        I915_WRITE(GEN8_GT_IIR(1), tmp);
                        ret = IRQ_HANDLED;
+
                        vcs = tmp >> GEN8_VCS1_IRQ_SHIFT;
+                       ring = &dev_priv->ring[VCS];
                        if (vcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[VCS]);
+                               notify_ring(dev, ring);
+                       if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
+
                        vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
+                       ring = &dev_priv->ring[VCS2];
                        if (vcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[VCS2]);
+                               notify_ring(dev, ring);
+                       if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT1)!\n");
        }
@@ -1677,9 +1694,13 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
                if (tmp) {
                        I915_WRITE(GEN8_GT_IIR(3), tmp);
                        ret = IRQ_HANDLED;
+
                        vcs = tmp >> GEN8_VECS_IRQ_SHIFT;
+                       ring = &dev_priv->ring[VECS];
                        if (vcs & GT_RENDER_USER_INTERRUPT)
-                               notify_ring(dev, &dev_priv->ring[VECS]);
+                               notify_ring(dev, ring);
+                       if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
+                               intel_execlists_handle_ctx_events(ring);
                } else
                        DRM_ERROR("The master control interrupt lied (GT3)!\n");
        }
@@ -1772,7 +1793,9 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
                                long_hpd = (dig_hotplug_reg >> dig_shift) & PORTB_HOTPLUG_LONG_DETECT;
                        }
 
-                       DRM_DEBUG_DRIVER("digital hpd port %d %d\n", port, long_hpd);
+                       DRM_DEBUG_DRIVER("digital hpd port %c - %s\n",
+                                        port_name(port),
+                                        long_hpd ? "long" : "short");
                        /* for long HPD pulses we want to have the digital queue happen,
                           but we still want HPD storm detection to function. */
                        if (long_hpd) {
@@ -3781,12 +3804,17 @@ static void gen8_gt_irq_postinstall(struct drm_i915_private *dev_priv)
        /* These are interrupts we'll toggle with the ring mask register */
        uint32_t gt_interrupts[] = {
                GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
                        GT_RENDER_L3_PARITY_ERROR_INTERRUPT |
-                       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
+                       GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT |
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT,
                GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
-                       GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT |
+                       GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT |
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT,
                0,
-               GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT
+               GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT |
+                       GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT
                };
 
        for (i = 0; i < ARRAY_SIZE(gt_interrupts); i++)
index 7f84dd263ee8966d414341a4d6471d52ca0578c3..139f490d464df8ae5ac1c400c877d3cb67b23988 100644 (file)
@@ -35,6 +35,7 @@ struct i915_params i915 __read_mostly = {
        .vbt_sdvo_panel_type = -1,
        .enable_rc6 = -1,
        .enable_fbc = -1,
+       .enable_execlists = 0,
        .enable_hangcheck = true,
        .enable_ppgtt = -1,
        .enable_psr = 0,
@@ -118,6 +119,11 @@ MODULE_PARM_DESC(enable_ppgtt,
        "Override PPGTT usage. "
        "(-1=auto [default], 0=disabled, 1=aliasing, 2=full)");
 
+module_param_named(enable_execlists, i915.enable_execlists, int, 0400);
+MODULE_PARM_DESC(enable_execlists,
+       "Override execlists usage. "
+       "(-1=auto, 0=disabled [default], 1=enabled)");
+
 module_param_named(enable_psr, i915.enable_psr, int, 0600);
 MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
 
index 7a6cc69cdc2b6eb6a8e97b95f82d27130e1d51d2..203062e93452cf96da0b3e482f979a51c9c13f03 100644 (file)
 #define   MI_SEMAPHORE_POLL            (1<<15)
 #define   MI_SEMAPHORE_SAD_GTE_SDD     (1<<12)
 #define MI_STORE_DWORD_IMM     MI_INSTR(0x20, 1)
+#define MI_STORE_DWORD_IMM_GEN8        MI_INSTR(0x20, 2)
 #define   MI_MEM_VIRTUAL       (1 << 22) /* 965+ only */
 #define MI_STORE_DWORD_INDEX   MI_INSTR(0x21, 1)
 #define   MI_STORE_DWORD_INDEX_SHIFT 2
  *   address/value pairs. Don't overdue it, though, x <= 2^4 must hold!
  */
 #define MI_LOAD_REGISTER_IMM(x)        MI_INSTR(0x22, 2*(x)-1)
+#define   MI_LRI_FORCE_POSTED          (1<<12)
 #define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*(x)-1)
 #define MI_STORE_REGISTER_MEM_GEN8(x) MI_INSTR(0x24, 3*(x)-1)
 #define   MI_SRM_LRM_GLOBAL_GTT                (1<<22)
@@ -1085,6 +1087,7 @@ enum punit_power_well {
 #define RING_ACTHD_UDW(base)   ((base)+0x5c)
 #define RING_NOPID(base)       ((base)+0x94)
 #define RING_IMR(base)         ((base)+0xa8)
+#define RING_HWSTAM(base)      ((base)+0x98)
 #define RING_TIMESTAMP(base)   ((base)+0x358)
 #define   TAIL_ADDR            0x001FFFF8
 #define   HEAD_WRAP_COUNT      0xFFE00000
@@ -1401,6 +1404,7 @@ enum punit_power_well {
 #define GT_BSD_CS_ERROR_INTERRUPT              (1 << 15)
 #define GT_BSD_USER_INTERRUPT                  (1 << 12)
 #define GT_RENDER_L3_PARITY_ERROR_INTERRUPT_S1 (1 << 11) /* hsw+; rsvd on snb, ivb, vlv */
+#define GT_CONTEXT_SWITCH_INTERRUPT            (1 <<  8)
 #define GT_RENDER_L3_PARITY_ERROR_INTERRUPT    (1 <<  5) /* !snb */
 #define GT_RENDER_PIPECTL_NOTIFY_INTERRUPT     (1 <<  4)
 #define GT_RENDER_CS_MASTER_ERROR_INTERRUPT    (1 <<  3)
@@ -4124,7 +4128,8 @@ enum punit_power_well {
 /* Old style CUR*CNTR flags (desktop 8xx) */
 #define   CURSOR_ENABLE                0x80000000
 #define   CURSOR_GAMMA_ENABLE  0x40000000
-#define   CURSOR_STRIDE_MASK   0x30000000
+#define   CURSOR_STRIDE_SHIFT  28
+#define   CURSOR_STRIDE(x)     ((ffs(x)-9) << CURSOR_STRIDE_SHIFT) /* 256,512,1k,2k */
 #define   CURSOR_PIPE_CSC_ENABLE (1<<24)
 #define   CURSOR_FORMAT_SHIFT  24
 #define   CURSOR_FORMAT_MASK   (0x07 << CURSOR_FORMAT_SHIFT)
index ca1f9a8a7d03bf7c41e403e2cbb305b3e91ec327..02d55843c78df627d0c54b2ffc26cc18c6bc4b46 100644 (file)
@@ -169,14 +169,14 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
                ddi_translations_dp = bdw_ddi_translations_dp;
                ddi_translations_edp = bdw_ddi_translations_edp;
                ddi_translations_hdmi = bdw_ddi_translations_hdmi;
-               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
+               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi) / 2;
                hdmi_800mV_0dB = 7;
        } else if (IS_HASWELL(dev)) {
                ddi_translations_fdi = hsw_ddi_translations_fdi;
                ddi_translations_dp = hsw_ddi_translations_dp;
                ddi_translations_edp = hsw_ddi_translations_dp;
                ddi_translations_hdmi = hsw_ddi_translations_hdmi;
-               n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi);
+               n_hdmi_entries = ARRAY_SIZE(hsw_ddi_translations_hdmi) / 2;
                hdmi_800mV_0dB = 6;
        } else {
                WARN(1, "ddi translation table missing\n");
@@ -184,7 +184,7 @@ static void intel_prepare_ddi_buffers(struct drm_device *dev, enum port port)
                ddi_translations_fdi = bdw_ddi_translations_fdi;
                ddi_translations_dp = bdw_ddi_translations_dp;
                ddi_translations_hdmi = bdw_ddi_translations_hdmi;
-               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi);
+               n_hdmi_entries = ARRAY_SIZE(bdw_ddi_translations_hdmi) / 2;
                hdmi_800mV_0dB = 7;
        }
 
index eab182d960f3c552839ebcfb0267f387b460f11e..ca8592e73644e48073c91dea03fee08e5b03419a 100644 (file)
@@ -1797,7 +1797,7 @@ static void intel_enable_shared_dpll(struct intel_crtc *crtc)
        pll->on = true;
 }
 
-void intel_disable_shared_dpll(struct intel_crtc *crtc)
+static void intel_disable_shared_dpll(struct intel_crtc *crtc)
 {
        struct drm_device *dev = crtc->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2082,35 +2082,28 @@ void intel_flush_primary_plane(struct drm_i915_private *dev_priv,
 
 /**
  * intel_enable_primary_hw_plane - enable the primary plane on a given pipe
- * @dev_priv: i915 private structure
- * @plane: plane to enable
- * @pipe: pipe being fed
+ * @plane:  plane to be enabled
+ * @crtc: crtc for the plane
  *
- * Enable @plane on @pipe, making sure that @pipe is running first.
+ * Enable @plane on @crtc, making sure that the pipe is running first.
  */
-static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
-                                         enum plane plane, enum pipe pipe)
+static void intel_enable_primary_hw_plane(struct drm_plane *plane,
+                                         struct drm_crtc *crtc)
 {
-       struct drm_device *dev = dev_priv->dev;
-       struct intel_crtc *intel_crtc =
-               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-       int reg;
-       u32 val;
+       struct drm_device *dev = plane->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
        /* If the pipe isn't enabled, we can't pump pixels and may hang */
-       assert_pipe_enabled(dev_priv, pipe);
+       assert_pipe_enabled(dev_priv, intel_crtc->pipe);
 
        if (intel_crtc->primary_enabled)
                return;
 
        intel_crtc->primary_enabled = true;
 
-       reg = DSPCNTR(plane);
-       val = I915_READ(reg);
-       WARN_ON(val & DISPLAY_PLANE_ENABLE);
-
-       I915_WRITE(reg, val | DISPLAY_PLANE_ENABLE);
-       intel_flush_primary_plane(dev_priv, plane);
+       dev_priv->display.update_primary_plane(crtc, plane->fb,
+                                              crtc->x, crtc->y);
 
        /*
         * BDW signals flip done immediately if the plane
@@ -2123,31 +2116,27 @@ static void intel_enable_primary_hw_plane(struct drm_i915_private *dev_priv,
 
 /**
  * intel_disable_primary_hw_plane - disable the primary hardware plane
- * @dev_priv: i915 private structure
- * @plane: plane to disable
- * @pipe: pipe consuming the data
+ * @plane: plane to be disabled
+ * @crtc: crtc for the plane
  *
- * Disable @plane; should be an independent operation.
+ * Disable @plane on @crtc, making sure that the pipe is running first.
  */
-static void intel_disable_primary_hw_plane(struct drm_i915_private *dev_priv,
-                                          enum plane plane, enum pipe pipe)
+static void intel_disable_primary_hw_plane(struct drm_plane *plane,
+                                          struct drm_crtc *crtc)
 {
-       struct intel_crtc *intel_crtc =
-               to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
-       int reg;
-       u32 val;
+       struct drm_device *dev = plane->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+       assert_pipe_enabled(dev_priv, intel_crtc->pipe);
 
        if (!intel_crtc->primary_enabled)
                return;
 
        intel_crtc->primary_enabled = false;
 
-       reg = DSPCNTR(plane);
-       val = I915_READ(reg);
-       WARN_ON((val & DISPLAY_PLANE_ENABLE) == 0);
-
-       I915_WRITE(reg, val & ~DISPLAY_PLANE_ENABLE);
-       intel_flush_primary_plane(dev_priv, plane);
+       dev_priv->display.update_primary_plane(crtc, plane->fb,
+                                              crtc->x, crtc->y);
 }
 
 static bool need_vtd_wa(struct drm_device *dev)
@@ -2388,12 +2377,35 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
        int plane = intel_crtc->plane;
        unsigned long linear_offset;
        u32 dspcntr;
-       u32 reg;
+       u32 reg = DSPCNTR(plane);
+
+       if (!intel_crtc->primary_enabled) {
+               I915_WRITE(reg, 0);
+               if (INTEL_INFO(dev)->gen >= 4)
+                       I915_WRITE(DSPSURF(plane), 0);
+               else
+                       I915_WRITE(DSPADDR(plane), 0);
+               POSTING_READ(reg);
+               return;
+       }
+
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+       dspcntr |= DISPLAY_PLANE_ENABLE;
+
+       if (INTEL_INFO(dev)->gen < 4) {
+               if (intel_crtc->pipe == PIPE_B)
+                       dspcntr |= DISPPLANE_SEL_PIPE_B;
+
+               /* pipesrc and dspsize control the size that is scaled from,
+                * which should always be the user's requested size.
+                */
+               I915_WRITE(DSPSIZE(plane),
+                          ((intel_crtc->config.pipe_src_h - 1) << 16) |
+                          (intel_crtc->config.pipe_src_w - 1));
+               I915_WRITE(DSPPOS(plane), 0);
+       }
 
-       reg = DSPCNTR(plane);
-       dspcntr = I915_READ(reg);
-       /* Mask out pixel format bits in case we change it */
-       dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
        switch (fb->pixel_format) {
        case DRM_FORMAT_C8:
                dspcntr |= DISPPLANE_8BPP;
@@ -2425,12 +2437,9 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
                BUG();
        }
 
-       if (INTEL_INFO(dev)->gen >= 4) {
-               if (obj->tiling_mode != I915_TILING_NONE)
-                       dspcntr |= DISPPLANE_TILED;
-               else
-                       dspcntr &= ~DISPPLANE_TILED;
-       }
+       if (INTEL_INFO(dev)->gen >= 4 &&
+           obj->tiling_mode != I915_TILING_NONE)
+               dspcntr |= DISPPLANE_TILED;
 
        if (IS_G4X(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
@@ -2474,12 +2483,22 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
        int plane = intel_crtc->plane;
        unsigned long linear_offset;
        u32 dspcntr;
-       u32 reg;
+       u32 reg = DSPCNTR(plane);
+
+       if (!intel_crtc->primary_enabled) {
+               I915_WRITE(reg, 0);
+               I915_WRITE(DSPSURF(plane), 0);
+               POSTING_READ(reg);
+               return;
+       }
+
+       dspcntr = DISPPLANE_GAMMA_ENABLE;
+
+       dspcntr |= DISPLAY_PLANE_ENABLE;
+
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               dspcntr |= DISPPLANE_PIPE_CSC_ENABLE;
 
-       reg = DSPCNTR(plane);
-       dspcntr = I915_READ(reg);
-       /* Mask out pixel format bits in case we change it */
-       dspcntr &= ~DISPPLANE_PIXFORMAT_MASK;
        switch (fb->pixel_format) {
        case DRM_FORMAT_C8:
                dspcntr |= DISPPLANE_8BPP;
@@ -2509,12 +2528,8 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
 
        if (obj->tiling_mode != I915_TILING_NONE)
                dspcntr |= DISPPLANE_TILED;
-       else
-               dspcntr &= ~DISPPLANE_TILED;
 
-       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
-               dspcntr &= ~DISPPLANE_TRICKLE_FEED_DISABLE;
-       else
+       if (!IS_HASWELL(dev) && !IS_BROADWELL(dev))
                dspcntr |= DISPPLANE_TRICKLE_FEED_DISABLE;
 
        I915_WRITE(reg, dspcntr);
@@ -3873,14 +3888,12 @@ static void intel_crtc_dpms_overlay(struct intel_crtc *intel_crtc, bool enable)
 static void intel_crtc_enable_planes(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
 
        drm_vblank_on(dev, pipe);
 
-       intel_enable_primary_hw_plane(dev_priv, plane, pipe);
+       intel_enable_primary_hw_plane(crtc->primary, crtc);
        intel_enable_planes(crtc);
        intel_crtc_update_cursor(crtc, true);
        intel_crtc_dpms_overlay(intel_crtc, true);
@@ -3917,7 +3930,7 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
        intel_crtc_dpms_overlay(intel_crtc, false);
        intel_crtc_update_cursor(crtc, false);
        intel_disable_planes(crtc);
-       intel_disable_primary_hw_plane(dev_priv, plane, pipe);
+       intel_disable_primary_hw_plane(crtc->primary, crtc);
 
        /*
         * FIXME: Once we grow proper nuclear flip support out of this we need
@@ -3936,7 +3949,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       enum plane plane = intel_crtc->plane;
 
        WARN_ON(!crtc->enabled);
 
@@ -3958,13 +3970,6 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 
        ironlake_set_pipeconf(crtc);
 
-       /* Set up the display plane register */
-       I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE);
-       POSTING_READ(DSPCNTR(plane));
-
-       dev_priv->display.update_primary_plane(crtc, crtc->primary->fb,
-                                              crtc->x, crtc->y);
-
        intel_crtc->active = true;
 
        intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
@@ -4049,7 +4054,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       enum plane plane = intel_crtc->plane;
 
        WARN_ON(!crtc->enabled);
 
@@ -4073,13 +4077,6 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
 
        intel_set_pipe_csc(crtc);
 
-       /* Set up the display plane register */
-       I915_WRITE(DSPCNTR(plane), DISPPLANE_GAMMA_ENABLE | DISPPLANE_PIPE_CSC_ENABLE);
-       POSTING_READ(DSPCNTR(plane));
-
-       dev_priv->display.update_primary_plane(crtc, crtc->primary->fb,
-                                              crtc->x, crtc->y);
-
        intel_crtc->active = true;
 
        intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
@@ -4628,13 +4625,10 @@ static void valleyview_modeset_global_resources(struct drm_device *dev)
 static void valleyview_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
        bool is_dsi;
-       u32 dspcntr;
 
        WARN_ON(!crtc->enabled);
 
@@ -4650,30 +4644,13 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
                        vlv_prepare_pll(intel_crtc);
        }
 
-       /* Set up the display plane register */
-       dspcntr = DISPPLANE_GAMMA_ENABLE;
-
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
        intel_set_pipe_timings(intel_crtc);
 
-       /* pipesrc and dspsize control the size that is scaled from,
-        * which should always be the user's requested size.
-        */
-       I915_WRITE(DSPSIZE(plane),
-                  ((intel_crtc->config.pipe_src_h - 1) << 16) |
-                  (intel_crtc->config.pipe_src_w - 1));
-       I915_WRITE(DSPPOS(plane), 0);
-
        i9xx_set_pipeconf(intel_crtc);
 
-       I915_WRITE(DSPCNTR(plane), dspcntr);
-       POSTING_READ(DSPCNTR(plane));
-
-       dev_priv->display.update_primary_plane(crtc, crtc->primary->fb,
-                                              crtc->x, crtc->y);
-
        intel_crtc->active = true;
 
        intel_set_cpu_fifo_underrun_reporting(dev, pipe, true);
@@ -4721,12 +4698,9 @@ static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
 static void i9xx_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_encoder *encoder;
        int pipe = intel_crtc->pipe;
-       int plane = intel_crtc->plane;
-       u32 dspcntr;
 
        WARN_ON(!crtc->enabled);
 
@@ -4735,35 +4709,13 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 
        i9xx_set_pll_dividers(intel_crtc);
 
-       /* Set up the display plane register */
-       dspcntr = DISPPLANE_GAMMA_ENABLE;
-
-       if (pipe == 0)
-               dspcntr &= ~DISPPLANE_SEL_PIPE_MASK;
-       else
-               dspcntr |= DISPPLANE_SEL_PIPE_B;
-
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
 
        intel_set_pipe_timings(intel_crtc);
 
-       /* pipesrc and dspsize control the size that is scaled from,
-        * which should always be the user's requested size.
-        */
-       I915_WRITE(DSPSIZE(plane),
-                  ((intel_crtc->config.pipe_src_h - 1) << 16) |
-                  (intel_crtc->config.pipe_src_w - 1));
-       I915_WRITE(DSPPOS(plane), 0);
-
        i9xx_set_pipeconf(intel_crtc);
 
-       I915_WRITE(DSPCNTR(plane), dspcntr);
-       POSTING_READ(DSPCNTR(plane));
-
-       dev_priv->display.update_primary_plane(crtc, crtc->primary->fb,
-                                              crtc->x, crtc->y);
-
        intel_crtc->active = true;
 
        if (!IS_GEN2(dev))
@@ -8095,74 +8047,62 @@ static void i845_update_cursor(struct drm_crtc *crtc, u32 base)
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       uint32_t cntl;
+       uint32_t cntl = 0, size = 0;
 
-       if (base != intel_crtc->cursor_base) {
-               /* On these chipsets we can only modify the base whilst
-                * the cursor is disabled.
-                */
-               if (intel_crtc->cursor_cntl) {
-                       I915_WRITE(_CURACNTR, 0);
-                       POSTING_READ(_CURACNTR);
-                       intel_crtc->cursor_cntl = 0;
+       if (base) {
+               unsigned int width = intel_crtc->cursor_width;
+               unsigned int height = intel_crtc->cursor_height;
+               unsigned int stride = roundup_pow_of_two(width) * 4;
+
+               switch (stride) {
+               default:
+                       WARN_ONCE(1, "Invalid cursor width/stride, width=%u, stride=%u\n",
+                                 width, stride);
+                       stride = 256;
+                       /* fallthrough */
+               case 256:
+               case 512:
+               case 1024:
+               case 2048:
+                       break;
                }
 
-               I915_WRITE(_CURABASE, base);
-               POSTING_READ(_CURABASE);
+               cntl |= CURSOR_ENABLE |
+                       CURSOR_GAMMA_ENABLE |
+                       CURSOR_FORMAT_ARGB |
+                       CURSOR_STRIDE(stride);
+
+               size = (height << 12) | width;
        }
 
-       /* XXX width must be 64, stride 256 => 0x00 << 28 */
-       cntl = 0;
-       if (base)
-               cntl = (CURSOR_ENABLE |
-                       CURSOR_GAMMA_ENABLE |
-                       CURSOR_FORMAT_ARGB);
-       if (intel_crtc->cursor_cntl != cntl) {
-               I915_WRITE(_CURACNTR, cntl);
+       if (intel_crtc->cursor_cntl != 0 &&
+           (intel_crtc->cursor_base != base ||
+            intel_crtc->cursor_size != size ||
+            intel_crtc->cursor_cntl != cntl)) {
+               /* On these chipsets we can only modify the base/size/stride
+                * whilst the cursor is disabled.
+                */
+               I915_WRITE(_CURACNTR, 0);
                POSTING_READ(_CURACNTR);
-               intel_crtc->cursor_cntl = cntl;
+               intel_crtc->cursor_cntl = 0;
        }
-}
 
-static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       int pipe = intel_crtc->pipe;
-       uint32_t cntl;
+       if (intel_crtc->cursor_base != base)
+               I915_WRITE(_CURABASE, base);
 
-       cntl = 0;
-       if (base) {
-               cntl = MCURSOR_GAMMA_ENABLE;
-               switch (intel_crtc->cursor_width) {
-                       case 64:
-                               cntl |= CURSOR_MODE_64_ARGB_AX;
-                               break;
-                       case 128:
-                               cntl |= CURSOR_MODE_128_ARGB_AX;
-                               break;
-                       case 256:
-                               cntl |= CURSOR_MODE_256_ARGB_AX;
-                               break;
-                       default:
-                               WARN_ON(1);
-                               return;
-               }
-               cntl |= pipe << 28; /* Connect to correct pipe */
+       if (intel_crtc->cursor_size != size) {
+               I915_WRITE(CURSIZE, size);
+               intel_crtc->cursor_size = size;
        }
+
        if (intel_crtc->cursor_cntl != cntl) {
-               I915_WRITE(CURCNTR(pipe), cntl);
-               POSTING_READ(CURCNTR(pipe));
+               I915_WRITE(_CURACNTR, cntl);
+               POSTING_READ(_CURACNTR);
                intel_crtc->cursor_cntl = cntl;
        }
-
-       /* and commit changes on next vblank */
-       I915_WRITE(CURBASE(pipe), base);
-       POSTING_READ(CURBASE(pipe));
 }
 
-static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
+static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -8187,6 +8127,7 @@ static void ivb_update_cursor(struct drm_crtc *crtc, u32 base)
                                WARN_ON(1);
                                return;
                }
+               cntl |= pipe << 28; /* Connect to correct pipe */
        }
        if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                cntl |= CURSOR_PIPE_CSC_ENABLE;
@@ -8246,15 +8187,50 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
 
        I915_WRITE(CURPOS(pipe), pos);
 
-       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
-               ivb_update_cursor(crtc, base);
-       else if (IS_845G(dev) || IS_I865G(dev))
+       if (IS_845G(dev) || IS_I865G(dev))
                i845_update_cursor(crtc, base);
        else
                i9xx_update_cursor(crtc, base);
        intel_crtc->cursor_base = base;
 }
 
+static bool cursor_size_ok(struct drm_device *dev,
+                          uint32_t width, uint32_t height)
+{
+       if (width == 0 || height == 0)
+               return false;
+
+       /*
+        * 845g/865g are special in that they are only limited by
+        * the width of their cursors, the height is arbitrary up to
+        * the precision of the register. Everything else requires
+        * square cursors, limited to a few power-of-two sizes.
+        */
+       if (IS_845G(dev) || IS_I865G(dev)) {
+               if ((width & 63) != 0)
+                       return false;
+
+               if (width > (IS_845G(dev) ? 64 : 512))
+                       return false;
+
+               if (height > 1023)
+                       return false;
+       } else {
+               switch (width | height) {
+               case 256:
+               case 128:
+                       if (IS_GEN2(dev))
+                               return false;
+               case 64:
+                       break;
+               default:
+                       return false;
+               }
+       }
+
+       return true;
+}
+
 /*
  * intel_crtc_cursor_set_obj - Set cursor to specified GEM object
  *
@@ -8267,10 +8243,9 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
                                     uint32_t width, uint32_t height)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        enum pipe pipe = intel_crtc->pipe;
-       unsigned old_width;
+       unsigned old_width, stride;
        uint32_t addr;
        int ret;
 
@@ -8284,14 +8259,13 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
        }
 
        /* Check for which cursor types we support */
-       if (!((width == 64 && height == 64) ||
-                       (width == 128 && height == 128 && !IS_GEN2(dev)) ||
-                       (width == 256 && height == 256 && !IS_GEN2(dev)))) {
+       if (!cursor_size_ok(dev, width, height)) {
                DRM_DEBUG("Cursor dimension not supported\n");
                return -EINVAL;
        }
 
-       if (obj->base.size < width * height * 4) {
+       stride = roundup_pow_of_two(width) * 4;
+       if (obj->base.size < stride * height) {
                DRM_DEBUG_KMS("buffer is too small\n");
                ret = -ENOMEM;
                goto fail;
@@ -8340,9 +8314,6 @@ static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
                addr = obj->phys_handle->busaddr;
        }
 
-       if (IS_GEN2(dev))
-               I915_WRITE(CURSIZE, (height << 12) | width);
-
  finish:
        if (intel_crtc->cursor_bo) {
                if (!INTEL_INFO(dev)->cursor_needs_physical)
@@ -9577,6 +9548,8 @@ static bool use_mmio_flip(struct intel_engine_cs *ring,
                return false;
        else if (i915.use_mmio_flip > 0)
                return true;
+       else if (i915.enable_execlists)
+               return true;
        else
                return ring != obj->ring;
 }
@@ -11380,7 +11353,6 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
                ret = intel_set_mode(set->crtc, set->mode,
                                     set->x, set->y, set->fb);
        } else if (config->fb_changed) {
-               struct drm_i915_private *dev_priv = dev->dev_private;
                struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
 
                intel_crtc_wait_for_pending_flips(set->crtc);
@@ -11394,8 +11366,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
                 */
                if (!intel_crtc->primary_enabled && ret == 0) {
                        WARN_ON(!intel_crtc->active);
-                       intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane,
-                                                     intel_crtc->pipe);
+                       intel_enable_primary_hw_plane(set->crtc->primary, set->crtc);
                }
 
                /*
@@ -11548,8 +11519,6 @@ static int
 intel_primary_plane_disable(struct drm_plane *plane)
 {
        struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct intel_crtc *intel_crtc;
 
        if (!plane->fb)
@@ -11572,8 +11541,8 @@ intel_primary_plane_disable(struct drm_plane *plane)
                goto disable_unpin;
 
        intel_crtc_wait_for_pending_flips(plane->crtc);
-       intel_disable_primary_hw_plane(dev_priv, intel_plane->plane,
-                                      intel_plane->pipe);
+       intel_disable_primary_hw_plane(plane, plane->crtc);
+
 disable_unpin:
        mutex_lock(&dev->struct_mutex);
        i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
@@ -11593,9 +11562,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
                             uint32_t src_w, uint32_t src_h)
 {
        struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
-       struct intel_plane *intel_plane = to_intel_plane(plane);
        struct drm_i915_gem_object *obj = intel_fb_obj(fb);
        struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
        struct drm_rect dest = {
@@ -11682,9 +11649,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
                                  INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe));
 
                if (intel_crtc->primary_enabled)
-                       intel_disable_primary_hw_plane(dev_priv,
-                                                      intel_plane->plane,
-                                                      intel_plane->pipe);
+                       intel_disable_primary_hw_plane(plane, crtc);
 
 
                if (plane->fb != fb)
@@ -11701,8 +11666,7 @@ intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
                return ret;
 
        if (!intel_crtc->primary_enabled)
-               intel_enable_primary_hw_plane(dev_priv, intel_crtc->plane,
-                                             intel_crtc->pipe);
+               intel_enable_primary_hw_plane(plane, crtc);
 
        return 0;
 }
@@ -11811,6 +11775,10 @@ intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
                return intel_crtc_cursor_set_obj(crtc, obj, crtc_w, crtc_h);
        } else {
                intel_crtc_update_cursor(crtc, visible);
+
+               intel_frontbuffer_flip(crtc->dev,
+                                      INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe));
+
                return 0;
        }
 }
@@ -11887,6 +11855,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
 
        intel_crtc->cursor_base = ~0;
        intel_crtc->cursor_cntl = ~0;
+       intel_crtc->cursor_size = ~0;
 
        BUG_ON(pipe >= ARRAY_SIZE(dev_priv->plane_to_crtc_mapping) ||
               dev_priv->plane_to_crtc_mapping[intel_crtc->plane] != NULL);
@@ -12404,29 +12373,27 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.get_display_clock_speed =
                        i830_get_display_clock_speed;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               if (IS_GEN5(dev)) {
-                       dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
-                       dev_priv->display.write_eld = ironlake_write_eld;
-               } else if (IS_GEN6(dev)) {
-                       dev_priv->display.fdi_link_train = gen6_fdi_link_train;
-                       dev_priv->display.write_eld = ironlake_write_eld;
-                       dev_priv->display.modeset_global_resources =
-                               snb_modeset_global_resources;
-               } else if (IS_IVYBRIDGE(dev)) {
-                       /* FIXME: detect B0+ stepping and use auto training */
-                       dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
-                       dev_priv->display.write_eld = ironlake_write_eld;
-                       dev_priv->display.modeset_global_resources =
-                               ivb_modeset_global_resources;
-               } else if (IS_HASWELL(dev) || IS_GEN8(dev)) {
-                       dev_priv->display.fdi_link_train = hsw_fdi_link_train;
-                       dev_priv->display.write_eld = haswell_write_eld;
-                       dev_priv->display.modeset_global_resources =
-                               haswell_modeset_global_resources;
-               }
-       } else if (IS_G4X(dev)) {
+       if (IS_G4X(dev)) {
                dev_priv->display.write_eld = g4x_write_eld;
+       } else if (IS_GEN5(dev)) {
+               dev_priv->display.fdi_link_train = ironlake_fdi_link_train;
+               dev_priv->display.write_eld = ironlake_write_eld;
+       } else if (IS_GEN6(dev)) {
+               dev_priv->display.fdi_link_train = gen6_fdi_link_train;
+               dev_priv->display.write_eld = ironlake_write_eld;
+               dev_priv->display.modeset_global_resources =
+                       snb_modeset_global_resources;
+       } else if (IS_IVYBRIDGE(dev)) {
+               /* FIXME: detect B0+ stepping and use auto training */
+               dev_priv->display.fdi_link_train = ivb_manual_fdi_link_train;
+               dev_priv->display.write_eld = ironlake_write_eld;
+               dev_priv->display.modeset_global_resources =
+                       ivb_modeset_global_resources;
+       } else if (IS_HASWELL(dev) || IS_GEN8(dev)) {
+               dev_priv->display.fdi_link_train = hsw_fdi_link_train;
+               dev_priv->display.write_eld = haswell_write_eld;
+               dev_priv->display.modeset_global_resources =
+                       haswell_modeset_global_resources;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.modeset_global_resources =
                        valleyview_modeset_global_resources;
@@ -12677,7 +12644,10 @@ void intel_modeset_init(struct drm_device *dev)
                dev->mode_config.max_height = 8192;
        }
 
-       if (IS_GEN2(dev)) {
+       if (IS_845G(dev) || IS_I865G(dev)) {
+               dev->mode_config.cursor_width = IS_845G(dev) ? 64 : 512;
+               dev->mode_config.cursor_height = 1023;
+       } else if (IS_GEN2(dev)) {
                dev->mode_config.cursor_width = GEN2_CURSOR_WIDTH;
                dev->mode_config.cursor_height = GEN2_CURSOR_HEIGHT;
        } else {
index 6db84bf0a92a2ca1d8b84f6adfae00ed30d38f3b..6a2256cf1f2a294aa9e42e0fd8ac66af222e0f16 100644 (file)
@@ -4059,7 +4059,8 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
        if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
                intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
 
-       DRM_DEBUG_KMS("got hpd irq on port %d - %s\n", intel_dig_port->port,
+       DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
+                     port_name(intel_dig_port->port),
                      long_hpd ? "long" : "short");
 
        power_domain = intel_display_port_power_domain(intel_encoder);
index 70cddaf29ae36636e583dbf2ec5df20d080a74b5..d683a2090249d2be5a91a0c61ae1289be5fe229b 100644 (file)
@@ -411,6 +411,7 @@ struct intel_crtc {
        uint32_t cursor_addr;
        int16_t cursor_width, cursor_height;
        uint32_t cursor_cntl;
+       uint32_t cursor_size;
        uint32_t cursor_base;
 
        struct intel_plane_config plane_config;
@@ -952,7 +953,7 @@ void intel_dvo_init(struct drm_device *dev);
 extern int intel_fbdev_init(struct drm_device *dev);
 extern void intel_fbdev_initial_config(struct drm_device *dev);
 extern void intel_fbdev_fini(struct drm_device *dev);
-extern void intel_fbdev_set_suspend(struct drm_device *dev, int state);
+extern void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous);
 extern void intel_fbdev_output_poll_changed(struct drm_device *dev);
 extern void intel_fbdev_restore_mode(struct drm_device *dev);
 #else
@@ -969,7 +970,7 @@ static inline void intel_fbdev_fini(struct drm_device *dev)
 {
 }
 
-static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state)
+static inline void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
 {
 }
 
index f475414671d8bdd5752a41fa8f4f6339470e365c..cf052a39558d255a8fd08eaff1097bbfbaa9cbbc 100644 (file)
@@ -26,6 +26,7 @@
 
 #include <linux/module.h>
 #include <linux/kernel.h>
+#include <linux/console.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
@@ -636,6 +637,15 @@ out:
        return false;
 }
 
+static void intel_fbdev_suspend_worker(struct work_struct *work)
+{
+       intel_fbdev_set_suspend(container_of(work,
+                                            struct drm_i915_private,
+                                            fbdev_suspend_work)->dev,
+                               FBINFO_STATE_RUNNING,
+                               true);
+}
+
 int intel_fbdev_init(struct drm_device *dev)
 {
        struct intel_fbdev *ifbdev;
@@ -662,6 +672,8 @@ int intel_fbdev_init(struct drm_device *dev)
        }
 
        dev_priv->fbdev = ifbdev;
+       INIT_WORK(&dev_priv->fbdev_suspend_work, intel_fbdev_suspend_worker);
+
        drm_fb_helper_single_add_all_connectors(&ifbdev->helper);
 
        return 0;
@@ -682,12 +694,14 @@ void intel_fbdev_fini(struct drm_device *dev)
        if (!dev_priv->fbdev)
                return;
 
+       flush_work(&dev_priv->fbdev_suspend_work);
+
        intel_fbdev_destroy(dev, dev_priv->fbdev);
        kfree(dev_priv->fbdev);
        dev_priv->fbdev = NULL;
 }
 
-void intel_fbdev_set_suspend(struct drm_device *dev, int state)
+void intel_fbdev_set_suspend(struct drm_device *dev, int state, bool synchronous)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_fbdev *ifbdev = dev_priv->fbdev;
@@ -698,6 +712,33 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
 
        info = ifbdev->helper.fbdev;
 
+       if (synchronous) {
+               /* Flush any pending work to turn the console on, and then
+                * wait to turn it off. It must be synchronous as we are
+                * about to suspend or unload the driver.
+                *
+                * Note that from within the work-handler, we cannot flush
+                * ourselves, so only flush outstanding work upon suspend!
+                */
+               if (state != FBINFO_STATE_RUNNING)
+                       flush_work(&dev_priv->fbdev_suspend_work);
+               console_lock();
+       } else {
+               /*
+                * The console lock can be pretty contented on resume due
+                * to all the printk activity.  Try to keep it out of the hot
+                * path of resume if possible.
+                */
+               WARN_ON(state != FBINFO_STATE_RUNNING);
+               if (!console_trylock()) {
+                       /* Don't block our own workqueue as this can
+                        * be run in parallel with other i915.ko tasks.
+                        */
+                       schedule_work(&dev_priv->fbdev_suspend_work);
+                       return;
+               }
+       }
+
        /* On resume from hibernation: If the object is shmemfs backed, it has
         * been restored from swap. If the object is stolen however, it will be
         * full of whatever garbage was left in there.
@@ -706,6 +747,7 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
                memset_io(info->screen_base, 0, info->screen_size);
 
        fb_set_suspend(info, state);
+       console_unlock();
 }
 
 void intel_fbdev_output_poll_changed(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
new file mode 100644 (file)
index 0000000..c096b9b
--- /dev/null
@@ -0,0 +1,1697 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Ben Widawsky <ben@bwidawsk.net>
+ *    Michel Thierry <michel.thierry@intel.com>
+ *    Thomas Daniel <thomas.daniel@intel.com>
+ *    Oscar Mateo <oscar.mateo@intel.com>
+ *
+ */
+
+/**
+ * DOC: Logical Rings, Logical Ring Contexts and Execlists
+ *
+ * Motivation:
+ * GEN8 brings an expansion of the HW contexts: "Logical Ring Contexts".
+ * These expanded contexts enable a number of new abilities, especially
+ * "Execlists" (also implemented in this file).
+ *
+ * One of the main differences with the legacy HW contexts is that logical
+ * ring contexts incorporate many more things to the context's state, like
+ * PDPs or ringbuffer control registers:
+ *
+ * The reason why PDPs are included in the context is straightforward: as
+ * PPGTTs (per-process GTTs) are actually per-context, having the PDPs
+ * contained there mean you don't need to do a ppgtt->switch_mm yourself,
+ * instead, the GPU will do it for you on the context switch.
+ *
+ * But, what about the ringbuffer control registers (head, tail, etc..)?
+ * shouldn't we just need a set of those per engine command streamer? This is
+ * where the name "Logical Rings" starts to make sense: by virtualizing the
+ * rings, the engine cs shifts to a new "ring buffer" with every context
+ * switch. When you want to submit a workload to the GPU you: A) choose your
+ * context, B) find its appropriate virtualized ring, C) write commands to it
+ * and then, finally, D) tell the GPU to switch to that context.
+ *
+ * Instead of the legacy MI_SET_CONTEXT, the way you tell the GPU to switch
+ * to a contexts is via a context execution list, ergo "Execlists".
+ *
+ * LRC implementation:
+ * Regarding the creation of contexts, we have:
+ *
+ * - One global default context.
+ * - One local default context for each opened fd.
+ * - One local extra context for each context create ioctl call.
+ *
+ * Now that ringbuffers belong per-context (and not per-engine, like before)
+ * and that contexts are uniquely tied to a given engine (and not reusable,
+ * like before) we need:
+ *
+ * - One ringbuffer per-engine inside each context.
+ * - One backing object per-engine inside each context.
+ *
+ * The global default context starts its life with these new objects fully
+ * allocated and populated. The local default context for each opened fd is
+ * more complex, because we don't know at creation time which engine is going
+ * to use them. To handle this, we have implemented a deferred creation of LR
+ * contexts:
+ *
+ * The local context starts its life as a hollow or blank holder, that only
+ * gets populated for a given engine once we receive an execbuffer. If later
+ * on we receive another execbuffer ioctl for the same context but a different
+ * engine, we allocate/populate a new ringbuffer and context backing object and
+ * so on.
+ *
+ * Finally, regarding local contexts created using the ioctl call: as they are
+ * only allowed with the render ring, we can allocate & populate them right
+ * away (no need to defer anything, at least for now).
+ *
+ * Execlists implementation:
+ * Execlists are the new method by which, on gen8+ hardware, workloads are
+ * submitted for execution (as opposed to the legacy, ringbuffer-based, method).
+ * This method works as follows:
+ *
+ * When a request is committed, its commands (the BB start and any leading or
+ * trailing commands, like the seqno breadcrumbs) are placed in the ringbuffer
+ * for the appropriate context. The tail pointer in the hardware context is not
+ * updated at this time, but instead, kept by the driver in the ringbuffer
+ * structure. A structure representing this request is added to a request queue
+ * for the appropriate engine: this structure contains a copy of the context's
+ * tail after the request was written to the ring buffer and a pointer to the
+ * context itself.
+ *
+ * If the engine's request queue was empty before the request was added, the
+ * queue is processed immediately. Otherwise the queue will be processed during
+ * a context switch interrupt. In any case, elements on the queue will get sent
+ * (in pairs) to the GPU's ExecLists Submit Port (ELSP, for short) with a
+ * globally unique 20-bits submission ID.
+ *
+ * When execution of a request completes, the GPU updates the context status
+ * buffer with a context complete event and generates a context switch interrupt.
+ * During the interrupt handling, the driver examines the events in the buffer:
+ * for each context complete event, if the announced ID matches that on the head
+ * of the request queue, then that request is retired and removed from the queue.
+ *
+ * After processing, if any requests were retired and the queue is not empty
+ * then a new execution list can be submitted. The two requests at the front of
+ * the queue are next to be submitted but since a context may not occur twice in
+ * an execution list, if subsequent requests have the same ID as the first then
+ * the two requests must be combined. This is done simply by discarding requests
+ * at the head of the queue until either only one requests is left (in which case
+ * we use a NULL second context) or the first two requests have unique IDs.
+ *
+ * By always executing the first two requests in the queue the driver ensures
+ * that the GPU is kept as busy as possible. In the case where a single context
+ * completes but a second context is still executing, the request for this second
+ * context will be at the head of the queue when we remove the first one. This
+ * request will then be resubmitted along with a new request for a different context,
+ * which will cause the hardware to continue executing the second request and queue
+ * the new request (the GPU detects the condition of a context getting preempted
+ * with the same context and optimizes the context switch flow by not doing
+ * preemption, but just sampling the new tail pointer).
+ *
+ */
+
+#include <drm/drmP.h>
+#include <drm/i915_drm.h>
+#include "i915_drv.h"
+
+#define GEN8_LR_CONTEXT_RENDER_SIZE (20 * PAGE_SIZE)
+#define GEN8_LR_CONTEXT_OTHER_SIZE (2 * PAGE_SIZE)
+
+#define GEN8_LR_CONTEXT_ALIGN 4096
+
+#define RING_EXECLIST_QFULL            (1 << 0x2)
+#define RING_EXECLIST1_VALID           (1 << 0x3)
+#define RING_EXECLIST0_VALID           (1 << 0x4)
+#define RING_EXECLIST_ACTIVE_STATUS    (3 << 0xE)
+#define RING_EXECLIST1_ACTIVE          (1 << 0x11)
+#define RING_EXECLIST0_ACTIVE          (1 << 0x12)
+
+#define GEN8_CTX_STATUS_IDLE_ACTIVE    (1 << 0)
+#define GEN8_CTX_STATUS_PREEMPTED      (1 << 1)
+#define GEN8_CTX_STATUS_ELEMENT_SWITCH (1 << 2)
+#define GEN8_CTX_STATUS_ACTIVE_IDLE    (1 << 3)
+#define GEN8_CTX_STATUS_COMPLETE       (1 << 4)
+#define GEN8_CTX_STATUS_LITE_RESTORE   (1 << 15)
+
+#define CTX_LRI_HEADER_0               0x01
+#define CTX_CONTEXT_CONTROL            0x02
+#define CTX_RING_HEAD                  0x04
+#define CTX_RING_TAIL                  0x06
+#define CTX_RING_BUFFER_START          0x08
+#define CTX_RING_BUFFER_CONTROL                0x0a
+#define CTX_BB_HEAD_U                  0x0c
+#define CTX_BB_HEAD_L                  0x0e
+#define CTX_BB_STATE                   0x10
+#define CTX_SECOND_BB_HEAD_U           0x12
+#define CTX_SECOND_BB_HEAD_L           0x14
+#define CTX_SECOND_BB_STATE            0x16
+#define CTX_BB_PER_CTX_PTR             0x18
+#define CTX_RCS_INDIRECT_CTX           0x1a
+#define CTX_RCS_INDIRECT_CTX_OFFSET    0x1c
+#define CTX_LRI_HEADER_1               0x21
+#define CTX_CTX_TIMESTAMP              0x22
+#define CTX_PDP3_UDW                   0x24
+#define CTX_PDP3_LDW                   0x26
+#define CTX_PDP2_UDW                   0x28
+#define CTX_PDP2_LDW                   0x2a
+#define CTX_PDP1_UDW                   0x2c
+#define CTX_PDP1_LDW                   0x2e
+#define CTX_PDP0_UDW                   0x30
+#define CTX_PDP0_LDW                   0x32
+#define CTX_LRI_HEADER_2               0x41
+#define CTX_R_PWR_CLK_STATE            0x42
+#define CTX_GPGPU_CSR_BASE_ADDRESS     0x44
+
+#define GEN8_CTX_VALID (1<<0)
+#define GEN8_CTX_FORCE_PD_RESTORE (1<<1)
+#define GEN8_CTX_FORCE_RESTORE (1<<2)
+#define GEN8_CTX_L3LLC_COHERENT (1<<5)
+#define GEN8_CTX_PRIVILEGE (1<<8)
+enum {
+       ADVANCED_CONTEXT = 0,
+       LEGACY_CONTEXT,
+       ADVANCED_AD_CONTEXT,
+       LEGACY_64B_CONTEXT
+};
+#define GEN8_CTX_MODE_SHIFT 3
+enum {
+       FAULT_AND_HANG = 0,
+       FAULT_AND_HALT, /* Debug only */
+       FAULT_AND_STREAM,
+       FAULT_AND_CONTINUE /* Unsupported */
+};
+#define GEN8_CTX_ID_SHIFT 32
+
+/**
+ * intel_sanitize_enable_execlists() - sanitize i915.enable_execlists
+ * @dev: DRM device.
+ * @enable_execlists: value of i915.enable_execlists module parameter.
+ *
+ * Only certain platforms support Execlists (the prerequisites being
+ * support for Logical Ring Contexts and Aliasing PPGTT or better),
+ * and only when enabled via module parameter.
+ *
+ * Return: 1 if Execlists is supported and has to be enabled.
+ */
+int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists)
+{
+       WARN_ON(i915.enable_ppgtt == -1);
+
+       if (enable_execlists == 0)
+               return 0;
+
+       if (HAS_LOGICAL_RING_CONTEXTS(dev) && USES_PPGTT(dev) &&
+           i915.use_mmio_flip >= 0)
+               return 1;
+
+       return 0;
+}
+
+/**
+ * intel_execlists_ctx_id() - get the Execlists Context ID
+ * @ctx_obj: Logical Ring Context backing object.
+ *
+ * Do not confuse with ctx->id! Unfortunately we have a name overload
+ * here: the old context ID we pass to userspace as a handler so that
+ * they can refer to a context, and the new context ID we pass to the
+ * ELSP so that the GPU can inform us of the context status via
+ * interrupts.
+ *
+ * Return: 20-bits globally unique context ID.
+ */
+u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj)
+{
+       u32 lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+
+       /* LRCA is required to be 4K aligned so the more significant 20 bits
+        * are globally unique */
+       return lrca >> 12;
+}
+
+static uint64_t execlists_ctx_descriptor(struct drm_i915_gem_object *ctx_obj)
+{
+       uint64_t desc;
+       uint64_t lrca = i915_gem_obj_ggtt_offset(ctx_obj);
+
+       WARN_ON(lrca & 0xFFFFFFFF00000FFFULL);
+
+       desc = GEN8_CTX_VALID;
+       desc |= LEGACY_CONTEXT << GEN8_CTX_MODE_SHIFT;
+       desc |= GEN8_CTX_L3LLC_COHERENT;
+       desc |= GEN8_CTX_PRIVILEGE;
+       desc |= lrca;
+       desc |= (u64)intel_execlists_ctx_id(ctx_obj) << GEN8_CTX_ID_SHIFT;
+
+       /* TODO: WaDisableLiteRestore when we start using semaphore
+        * signalling between Command Streamers */
+       /* desc |= GEN8_CTX_FORCE_RESTORE; */
+
+       return desc;
+}
+
+static void execlists_elsp_write(struct intel_engine_cs *ring,
+                                struct drm_i915_gem_object *ctx_obj0,
+                                struct drm_i915_gem_object *ctx_obj1)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       uint64_t temp = 0;
+       uint32_t desc[4];
+       unsigned long flags;
+
+       /* XXX: You must always write both descriptors in the order below. */
+       if (ctx_obj1)
+               temp = execlists_ctx_descriptor(ctx_obj1);
+       else
+               temp = 0;
+       desc[1] = (u32)(temp >> 32);
+       desc[0] = (u32)temp;
+
+       temp = execlists_ctx_descriptor(ctx_obj0);
+       desc[3] = (u32)(temp >> 32);
+       desc[2] = (u32)temp;
+
+       /* Set Force Wakeup bit to prevent GT from entering C6 while ELSP writes
+        * are in progress.
+        *
+        * The other problem is that we can't just call gen6_gt_force_wake_get()
+        * because that function calls intel_runtime_pm_get(), which might sleep.
+        * Instead, we do the runtime_pm_get/put when creating/destroying requests.
+        */
+       spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+       if (dev_priv->uncore.forcewake_count++ == 0)
+               dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
+
+       I915_WRITE(RING_ELSP(ring), desc[1]);
+       I915_WRITE(RING_ELSP(ring), desc[0]);
+       I915_WRITE(RING_ELSP(ring), desc[3]);
+       /* The context is automatically loaded after the following */
+       I915_WRITE(RING_ELSP(ring), desc[2]);
+
+       /* ELSP is a wo register, so use another nearby reg for posting instead */
+       POSTING_READ(RING_EXECLIST_STATUS(ring));
+
+       /* Release Force Wakeup (see the big comment above). */
+       spin_lock_irqsave(&dev_priv->uncore.lock, flags);
+       if (--dev_priv->uncore.forcewake_count == 0)
+               dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
+}
+
+static int execlists_ctx_write_tail(struct drm_i915_gem_object *ctx_obj, u32 tail)
+{
+       struct page *page;
+       uint32_t *reg_state;
+
+       page = i915_gem_object_get_page(ctx_obj, 1);
+       reg_state = kmap_atomic(page);
+
+       reg_state[CTX_RING_TAIL+1] = tail;
+
+       kunmap_atomic(reg_state);
+
+       return 0;
+}
+
+static int execlists_submit_context(struct intel_engine_cs *ring,
+                                   struct intel_context *to0, u32 tail0,
+                                   struct intel_context *to1, u32 tail1)
+{
+       struct drm_i915_gem_object *ctx_obj0;
+       struct drm_i915_gem_object *ctx_obj1 = NULL;
+
+       ctx_obj0 = to0->engine[ring->id].state;
+       BUG_ON(!ctx_obj0);
+       WARN_ON(!i915_gem_obj_is_pinned(ctx_obj0));
+
+       execlists_ctx_write_tail(ctx_obj0, tail0);
+
+       if (to1) {
+               ctx_obj1 = to1->engine[ring->id].state;
+               BUG_ON(!ctx_obj1);
+               WARN_ON(!i915_gem_obj_is_pinned(ctx_obj1));
+
+               execlists_ctx_write_tail(ctx_obj1, tail1);
+       }
+
+       execlists_elsp_write(ring, ctx_obj0, ctx_obj1);
+
+       return 0;
+}
+
+static void execlists_context_unqueue(struct intel_engine_cs *ring)
+{
+       struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
+       struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       assert_spin_locked(&ring->execlist_lock);
+
+       if (list_empty(&ring->execlist_queue))
+               return;
+
+       /* Try to read in pairs */
+       list_for_each_entry_safe(cursor, tmp, &ring->execlist_queue,
+                                execlist_link) {
+               if (!req0) {
+                       req0 = cursor;
+               } else if (req0->ctx == cursor->ctx) {
+                       /* Same ctx: ignore first request, as second request
+                        * will update tail past first request's workload */
+                       cursor->elsp_submitted = req0->elsp_submitted;
+                       list_del(&req0->execlist_link);
+                       queue_work(dev_priv->wq, &req0->work);
+                       req0 = cursor;
+               } else {
+                       req1 = cursor;
+                       break;
+               }
+       }
+
+       WARN_ON(req1 && req1->elsp_submitted);
+
+       WARN_ON(execlists_submit_context(ring, req0->ctx, req0->tail,
+                                        req1 ? req1->ctx : NULL,
+                                        req1 ? req1->tail : 0));
+
+       req0->elsp_submitted++;
+       if (req1)
+               req1->elsp_submitted++;
+}
+
+static bool execlists_check_remove_request(struct intel_engine_cs *ring,
+                                          u32 request_id)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       struct intel_ctx_submit_request *head_req;
+
+       assert_spin_locked(&ring->execlist_lock);
+
+       head_req = list_first_entry_or_null(&ring->execlist_queue,
+                                           struct intel_ctx_submit_request,
+                                           execlist_link);
+
+       if (head_req != NULL) {
+               struct drm_i915_gem_object *ctx_obj =
+                               head_req->ctx->engine[ring->id].state;
+               if (intel_execlists_ctx_id(ctx_obj) == request_id) {
+                       WARN(head_req->elsp_submitted == 0,
+                            "Never submitted head request\n");
+
+                       if (--head_req->elsp_submitted <= 0) {
+                               list_del(&head_req->execlist_link);
+                               queue_work(dev_priv->wq, &head_req->work);
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+/**
+ * intel_execlists_handle_ctx_events() - handle Context Switch interrupts
+ * @ring: Engine Command Streamer to handle.
+ *
+ * Check the unread Context Status Buffers and manage the submission of new
+ * contexts to the ELSP accordingly.
+ */
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       u32 status_pointer;
+       u8 read_pointer;
+       u8 write_pointer;
+       u32 status;
+       u32 status_id;
+       u32 submit_contexts = 0;
+
+       status_pointer = I915_READ(RING_CONTEXT_STATUS_PTR(ring));
+
+       read_pointer = ring->next_context_status_buffer;
+       write_pointer = status_pointer & 0x07;
+       if (read_pointer > write_pointer)
+               write_pointer += 6;
+
+       spin_lock(&ring->execlist_lock);
+
+       while (read_pointer < write_pointer) {
+               read_pointer++;
+               status = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
+                               (read_pointer % 6) * 8);
+               status_id = I915_READ(RING_CONTEXT_STATUS_BUF(ring) +
+                               (read_pointer % 6) * 8 + 4);
+
+               if (status & GEN8_CTX_STATUS_PREEMPTED) {
+                       if (status & GEN8_CTX_STATUS_LITE_RESTORE) {
+                               if (execlists_check_remove_request(ring, status_id))
+                                       WARN(1, "Lite Restored request removed from queue\n");
+                       } else
+                               WARN(1, "Preemption without Lite Restore\n");
+               }
+
+                if ((status & GEN8_CTX_STATUS_ACTIVE_IDLE) ||
+                    (status & GEN8_CTX_STATUS_ELEMENT_SWITCH)) {
+                       if (execlists_check_remove_request(ring, status_id))
+                               submit_contexts++;
+               }
+       }
+
+       if (submit_contexts != 0)
+               execlists_context_unqueue(ring);
+
+       spin_unlock(&ring->execlist_lock);
+
+       WARN(submit_contexts > 2, "More than two context complete events?\n");
+       ring->next_context_status_buffer = write_pointer % 6;
+
+       I915_WRITE(RING_CONTEXT_STATUS_PTR(ring),
+                  ((u32)ring->next_context_status_buffer & 0x07) << 8);
+}
+
+static void execlists_free_request_task(struct work_struct *work)
+{
+       struct intel_ctx_submit_request *req =
+               container_of(work, struct intel_ctx_submit_request, work);
+       struct drm_device *dev = req->ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       intel_runtime_pm_put(dev_priv);
+
+       mutex_lock(&dev->struct_mutex);
+       i915_gem_context_unreference(req->ctx);
+       mutex_unlock(&dev->struct_mutex);
+
+       kfree(req);
+}
+
+static int execlists_context_queue(struct intel_engine_cs *ring,
+                                  struct intel_context *to,
+                                  u32 tail)
+{
+       struct intel_ctx_submit_request *req = NULL, *cursor;
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       unsigned long flags;
+       int num_elements = 0;
+
+       req = kzalloc(sizeof(*req), GFP_KERNEL);
+       if (req == NULL)
+               return -ENOMEM;
+       req->ctx = to;
+       i915_gem_context_reference(req->ctx);
+       req->ring = ring;
+       req->tail = tail;
+       INIT_WORK(&req->work, execlists_free_request_task);
+
+       intel_runtime_pm_get(dev_priv);
+
+       spin_lock_irqsave(&ring->execlist_lock, flags);
+
+       list_for_each_entry(cursor, &ring->execlist_queue, execlist_link)
+               if (++num_elements > 2)
+                       break;
+
+       if (num_elements > 2) {
+               struct intel_ctx_submit_request *tail_req;
+
+               tail_req = list_last_entry(&ring->execlist_queue,
+                                          struct intel_ctx_submit_request,
+                                          execlist_link);
+
+               if (to == tail_req->ctx) {
+                       WARN(tail_req->elsp_submitted != 0,
+                            "More than 2 already-submitted reqs queued\n");
+                       list_del(&tail_req->execlist_link);
+                       queue_work(dev_priv->wq, &tail_req->work);
+               }
+       }
+
+       list_add_tail(&req->execlist_link, &ring->execlist_queue);
+       if (num_elements == 0)
+               execlists_context_unqueue(ring);
+
+       spin_unlock_irqrestore(&ring->execlist_lock, flags);
+
+       return 0;
+}
+
+static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       uint32_t flush_domains;
+       int ret;
+
+       flush_domains = 0;
+       if (ring->gpu_caches_dirty)
+               flush_domains = I915_GEM_GPU_DOMAINS;
+
+       ret = ring->emit_flush(ringbuf, I915_GEM_GPU_DOMAINS, flush_domains);
+       if (ret)
+               return ret;
+
+       ring->gpu_caches_dirty = false;
+       return 0;
+}
+
+static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf,
+                                struct list_head *vmas)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct i915_vma *vma;
+       uint32_t flush_domains = 0;
+       bool flush_chipset = false;
+       int ret;
+
+       list_for_each_entry(vma, vmas, exec_list) {
+               struct drm_i915_gem_object *obj = vma->obj;
+
+               ret = i915_gem_object_sync(obj, ring);
+               if (ret)
+                       return ret;
+
+               if (obj->base.write_domain & I915_GEM_DOMAIN_CPU)
+                       flush_chipset |= i915_gem_clflush_object(obj, false);
+
+               flush_domains |= obj->base.write_domain;
+       }
+
+       if (flush_domains & I915_GEM_DOMAIN_GTT)
+               wmb();
+
+       /* Unconditionally invalidate gpu caches and ensure that we do flush
+        * any residual writes from the previous batch.
+        */
+       return logical_ring_invalidate_all_caches(ringbuf);
+}
+
+/**
+ * execlists_submission() - submit a batchbuffer for execution, Execlists style
+ * @dev: DRM device.
+ * @file: DRM file.
+ * @ring: Engine Command Streamer to submit to.
+ * @ctx: Context to employ for this submission.
+ * @args: execbuffer call arguments.
+ * @vmas: list of vmas.
+ * @batch_obj: the batchbuffer to submit.
+ * @exec_start: batchbuffer start virtual address pointer.
+ * @flags: translated execbuffer call flags.
+ *
+ * This is the evil twin version of i915_gem_ringbuffer_submission. It abstracts
+ * away the submission details of the execbuffer ioctl call.
+ *
+ * Return: non-zero if the submission fails.
+ */
+int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
+                              struct intel_engine_cs *ring,
+                              struct intel_context *ctx,
+                              struct drm_i915_gem_execbuffer2 *args,
+                              struct list_head *vmas,
+                              struct drm_i915_gem_object *batch_obj,
+                              u64 exec_start, u32 flags)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ringbuffer *ringbuf = ctx->engine[ring->id].ringbuf;
+       int instp_mode;
+       u32 instp_mask;
+       int ret;
+
+       instp_mode = args->flags & I915_EXEC_CONSTANTS_MASK;
+       instp_mask = I915_EXEC_CONSTANTS_MASK;
+       switch (instp_mode) {
+       case I915_EXEC_CONSTANTS_REL_GENERAL:
+       case I915_EXEC_CONSTANTS_ABSOLUTE:
+       case I915_EXEC_CONSTANTS_REL_SURFACE:
+               if (instp_mode != 0 && ring != &dev_priv->ring[RCS]) {
+                       DRM_DEBUG("non-0 rel constants mode on non-RCS\n");
+                       return -EINVAL;
+               }
+
+               if (instp_mode != dev_priv->relative_constants_mode) {
+                       if (instp_mode == I915_EXEC_CONSTANTS_REL_SURFACE) {
+                               DRM_DEBUG("rel surface constants mode invalid on gen5+\n");
+                               return -EINVAL;
+                       }
+
+                       /* The HW changed the meaning on this bit on gen6 */
+                       instp_mask &= ~I915_EXEC_CONSTANTS_REL_SURFACE;
+               }
+               break;
+       default:
+               DRM_DEBUG("execbuf with unknown constants: %d\n", instp_mode);
+               return -EINVAL;
+       }
+
+       if (args->num_cliprects != 0) {
+               DRM_DEBUG("clip rectangles are only valid on pre-gen5\n");
+               return -EINVAL;
+       } else {
+               if (args->DR4 == 0xffffffff) {
+                       DRM_DEBUG("UXA submitting garbage DR4, fixing up\n");
+                       args->DR4 = 0;
+               }
+
+               if (args->DR1 || args->DR4 || args->cliprects_ptr) {
+                       DRM_DEBUG("0 cliprects but dirt in cliprects fields\n");
+                       return -EINVAL;
+               }
+       }
+
+       if (args->flags & I915_EXEC_GEN7_SOL_RESET) {
+               DRM_DEBUG("sol reset is gen7 only\n");
+               return -EINVAL;
+       }
+
+       ret = execlists_move_to_gpu(ringbuf, vmas);
+       if (ret)
+               return ret;
+
+       if (ring == &dev_priv->ring[RCS] &&
+           instp_mode != dev_priv->relative_constants_mode) {
+               ret = intel_logical_ring_begin(ringbuf, 4);
+               if (ret)
+                       return ret;
+
+               intel_logical_ring_emit(ringbuf, MI_NOOP);
+               intel_logical_ring_emit(ringbuf, MI_LOAD_REGISTER_IMM(1));
+               intel_logical_ring_emit(ringbuf, INSTPM);
+               intel_logical_ring_emit(ringbuf, instp_mask << 16 | instp_mode);
+               intel_logical_ring_advance(ringbuf);
+
+               dev_priv->relative_constants_mode = instp_mode;
+       }
+
+       ret = ring->emit_bb_start(ringbuf, exec_start, flags);
+       if (ret)
+               return ret;
+
+       i915_gem_execbuffer_move_to_active(vmas, ring);
+       i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
+
+       return 0;
+}
+
+void intel_logical_ring_stop(struct intel_engine_cs *ring)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+       int ret;
+
+       if (!intel_ring_initialized(ring))
+               return;
+
+       ret = intel_ring_idle(ring);
+       if (ret && !i915_reset_in_progress(&to_i915(ring->dev)->gpu_error))
+               DRM_ERROR("failed to quiesce %s whilst cleaning up: %d\n",
+                         ring->name, ret);
+
+       /* TODO: Is this correct with Execlists enabled? */
+       I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING));
+       if (wait_for_atomic((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
+               DRM_ERROR("%s :timed out trying to stop ring\n", ring->name);
+               return;
+       }
+       I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING));
+}
+
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       int ret;
+
+       if (!ring->gpu_caches_dirty)
+               return 0;
+
+       ret = ring->emit_flush(ringbuf, 0, I915_GEM_GPU_DOMAINS);
+       if (ret)
+               return ret;
+
+       ring->gpu_caches_dirty = false;
+       return 0;
+}
+
+/**
+ * intel_logical_ring_advance_and_submit() - advance the tail and submit the workload
+ * @ringbuf: Logical Ringbuffer to advance.
+ *
+ * The tail is updated in our logical ringbuffer struct, not in the actual context. What
+ * really happens during submission is that the context and current tail will be placed
+ * on a queue waiting for the ELSP to be ready to accept a new context submission. At that
+ * point, the tail *inside* the context is updated and the ELSP written to.
+ */
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct intel_context *ctx = ringbuf->FIXME_lrc_ctx;
+
+       intel_logical_ring_advance(ringbuf);
+
+       if (intel_ring_stopped(ring))
+               return;
+
+       execlists_context_queue(ring, ctx, ringbuf->tail);
+}
+
+static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
+                                   struct intel_context *ctx)
+{
+       if (ring->outstanding_lazy_seqno)
+               return 0;
+
+       if (ring->preallocated_lazy_request == NULL) {
+               struct drm_i915_gem_request *request;
+
+               request = kmalloc(sizeof(*request), GFP_KERNEL);
+               if (request == NULL)
+                       return -ENOMEM;
+
+               /* Hold a reference to the context this request belongs to
+                * (we will need it when the time comes to emit/retire the
+                * request).
+                */
+               request->ctx = ctx;
+               i915_gem_context_reference(request->ctx);
+
+               ring->preallocated_lazy_request = request;
+       }
+
+       return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno);
+}
+
+static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf,
+                                    int bytes)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct drm_i915_gem_request *request;
+       u32 seqno = 0;
+       int ret;
+
+       if (ringbuf->last_retired_head != -1) {
+               ringbuf->head = ringbuf->last_retired_head;
+               ringbuf->last_retired_head = -1;
+
+               ringbuf->space = intel_ring_space(ringbuf);
+               if (ringbuf->space >= bytes)
+                       return 0;
+       }
+
+       list_for_each_entry(request, &ring->request_list, list) {
+               if (__intel_ring_space(request->tail, ringbuf->tail,
+                                      ringbuf->size) >= bytes) {
+                       seqno = request->seqno;
+                       break;
+               }
+       }
+
+       if (seqno == 0)
+               return -ENOSPC;
+
+       ret = i915_wait_seqno(ring, seqno);
+       if (ret)
+               return ret;
+
+       i915_gem_retire_requests_ring(ring);
+       ringbuf->head = ringbuf->last_retired_head;
+       ringbuf->last_retired_head = -1;
+
+       ringbuf->space = intel_ring_space(ringbuf);
+       return 0;
+}
+
+static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,
+                                      int bytes)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long end;
+       int ret;
+
+       ret = logical_ring_wait_request(ringbuf, bytes);
+       if (ret != -ENOSPC)
+               return ret;
+
+       /* Force the context submission in case we have been skipping it */
+       intel_logical_ring_advance_and_submit(ringbuf);
+
+       /* With GEM the hangcheck timer should kick us out of the loop,
+        * leaving it early runs the risk of corrupting GEM state (due
+        * to running on almost untested codepaths). But on resume
+        * timers don't work yet, so prevent a complete hang in that
+        * case by choosing an insanely large timeout. */
+       end = jiffies + 60 * HZ;
+
+       do {
+               ringbuf->head = I915_READ_HEAD(ring);
+               ringbuf->space = intel_ring_space(ringbuf);
+               if (ringbuf->space >= bytes) {
+                       ret = 0;
+                       break;
+               }
+
+               msleep(1);
+
+               if (dev_priv->mm.interruptible && signal_pending(current)) {
+                       ret = -ERESTARTSYS;
+                       break;
+               }
+
+               ret = i915_gem_check_wedge(&dev_priv->gpu_error,
+                                          dev_priv->mm.interruptible);
+               if (ret)
+                       break;
+
+               if (time_after(jiffies, end)) {
+                       ret = -EBUSY;
+                       break;
+               }
+       } while (1);
+
+       return ret;
+}
+
+static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf)
+{
+       uint32_t __iomem *virt;
+       int rem = ringbuf->size - ringbuf->tail;
+
+       if (ringbuf->space < rem) {
+               int ret = logical_ring_wait_for_space(ringbuf, rem);
+
+               if (ret)
+                       return ret;
+       }
+
+       virt = ringbuf->virtual_start + ringbuf->tail;
+       rem /= 4;
+       while (rem--)
+               iowrite32(MI_NOOP, virt++);
+
+       ringbuf->tail = 0;
+       ringbuf->space = intel_ring_space(ringbuf);
+
+       return 0;
+}
+
+static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, int bytes)
+{
+       int ret;
+
+       if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) {
+               ret = logical_ring_wrap_buffer(ringbuf);
+               if (unlikely(ret))
+                       return ret;
+       }
+
+       if (unlikely(ringbuf->space < bytes)) {
+               ret = logical_ring_wait_for_space(ringbuf, bytes);
+               if (unlikely(ret))
+                       return ret;
+       }
+
+       return 0;
+}
+
+/**
+ * intel_logical_ring_begin() - prepare the logical ringbuffer to accept some commands
+ *
+ * @ringbuf: Logical ringbuffer.
+ * @num_dwords: number of DWORDs that we plan to write to the ringbuffer.
+ *
+ * The ringbuffer might not be ready to accept the commands right away (maybe it needs to
+ * be wrapped, or wait a bit for the tail to be updated). This function takes care of that
+ * and also preallocates a request (every workload submission is still mediated through
+ * requests, same as it did with legacy ringbuffer submission).
+ *
+ * Return: non-zero if the ringbuffer is not ready to be written to.
+ */
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = i915_gem_check_wedge(&dev_priv->gpu_error,
+                                  dev_priv->mm.interruptible);
+       if (ret)
+               return ret;
+
+       ret = logical_ring_prepare(ringbuf, num_dwords * sizeof(uint32_t));
+       if (ret)
+               return ret;
+
+       /* Preallocate the olr before touching the ring */
+       ret = logical_ring_alloc_seqno(ring, ringbuf->FIXME_lrc_ctx);
+       if (ret)
+               return ret;
+
+       ringbuf->space -= num_dwords * sizeof(uint32_t);
+       return 0;
+}
+
+static int gen8_init_common_ring(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
+       I915_WRITE(RING_HWSTAM(ring->mmio_base), 0xffffffff);
+
+       I915_WRITE(RING_MODE_GEN7(ring),
+                  _MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
+                  _MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
+       POSTING_READ(RING_MODE_GEN7(ring));
+       DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name);
+
+       memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
+
+       return 0;
+}
+
+static int gen8_init_render_ring(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = gen8_init_common_ring(ring);
+       if (ret)
+               return ret;
+
+       /* 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,bdw,chv
+        */
+       I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
+
+       ret = intel_init_pipe_control(ring);
+       if (ret)
+               return ret;
+
+       I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
+
+       return ret;
+}
+
+static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf,
+                             u64 offset, unsigned flags)
+{
+       bool ppgtt = !(flags & I915_DISPATCH_SECURE);
+       int ret;
+
+       ret = intel_logical_ring_begin(ringbuf, 4);
+       if (ret)
+               return ret;
+
+       /* FIXME(BDW): Address space and security selectors. */
+       intel_logical_ring_emit(ringbuf, MI_BATCH_BUFFER_START_GEN8 | (ppgtt<<8));
+       intel_logical_ring_emit(ringbuf, lower_32_bits(offset));
+       intel_logical_ring_emit(ringbuf, upper_32_bits(offset));
+       intel_logical_ring_emit(ringbuf, MI_NOOP);
+       intel_logical_ring_advance(ringbuf);
+
+       return 0;
+}
+
+static bool gen8_logical_ring_get_irq(struct intel_engine_cs *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->irq_lock, flags);
+       if (ring->irq_refcount++ == 0) {
+               I915_WRITE_IMR(ring, ~(ring->irq_enable_mask | ring->irq_keep_mask));
+               POSTING_READ(RING_IMR(ring->mmio_base));
+       }
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+
+       return true;
+}
+
+static void gen8_logical_ring_put_irq(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       unsigned long flags;
+
+       spin_lock_irqsave(&dev_priv->irq_lock, flags);
+       if (--ring->irq_refcount == 0) {
+               I915_WRITE_IMR(ring, ~ring->irq_keep_mask);
+               POSTING_READ(RING_IMR(ring->mmio_base));
+       }
+       spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
+}
+
+static int gen8_emit_flush(struct intel_ringbuffer *ringbuf,
+                          u32 invalidate_domains,
+                          u32 unused)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       uint32_t cmd;
+       int ret;
+
+       ret = intel_logical_ring_begin(ringbuf, 4);
+       if (ret)
+               return ret;
+
+       cmd = MI_FLUSH_DW + 1;
+
+       if (ring == &dev_priv->ring[VCS]) {
+               if (invalidate_domains & I915_GEM_GPU_DOMAINS)
+                       cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD |
+                               MI_FLUSH_DW_STORE_INDEX |
+                               MI_FLUSH_DW_OP_STOREDW;
+       } else {
+               if (invalidate_domains & I915_GEM_DOMAIN_RENDER)
+                       cmd |= MI_INVALIDATE_TLB | MI_FLUSH_DW_STORE_INDEX |
+                               MI_FLUSH_DW_OP_STOREDW;
+       }
+
+       intel_logical_ring_emit(ringbuf, cmd);
+       intel_logical_ring_emit(ringbuf,
+                               I915_GEM_HWS_SCRATCH_ADDR |
+                               MI_FLUSH_DW_USE_GTT);
+       intel_logical_ring_emit(ringbuf, 0); /* upper addr */
+       intel_logical_ring_emit(ringbuf, 0); /* value */
+       intel_logical_ring_advance(ringbuf);
+
+       return 0;
+}
+
+static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf,
+                                 u32 invalidate_domains,
+                                 u32 flush_domains)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       u32 scratch_addr = ring->scratch.gtt_offset + 2 * CACHELINE_BYTES;
+       u32 flags = 0;
+       int ret;
+
+       flags |= PIPE_CONTROL_CS_STALL;
+
+       if (flush_domains) {
+               flags |= PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH;
+               flags |= PIPE_CONTROL_DEPTH_CACHE_FLUSH;
+       }
+
+       if (invalidate_domains) {
+               flags |= PIPE_CONTROL_TLB_INVALIDATE;
+               flags |= PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_VF_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_CONST_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_STATE_CACHE_INVALIDATE;
+               flags |= PIPE_CONTROL_QW_WRITE;
+               flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
+       }
+
+       ret = intel_logical_ring_begin(ringbuf, 6);
+       if (ret)
+               return ret;
+
+       intel_logical_ring_emit(ringbuf, GFX_OP_PIPE_CONTROL(6));
+       intel_logical_ring_emit(ringbuf, flags);
+       intel_logical_ring_emit(ringbuf, scratch_addr);
+       intel_logical_ring_emit(ringbuf, 0);
+       intel_logical_ring_emit(ringbuf, 0);
+       intel_logical_ring_emit(ringbuf, 0);
+       intel_logical_ring_advance(ringbuf);
+
+       return 0;
+}
+
+static u32 gen8_get_seqno(struct intel_engine_cs *ring, bool lazy_coherency)
+{
+       return intel_read_status_page(ring, I915_GEM_HWS_INDEX);
+}
+
+static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno)
+{
+       intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
+}
+
+static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
+{
+       struct intel_engine_cs *ring = ringbuf->ring;
+       u32 cmd;
+       int ret;
+
+       ret = intel_logical_ring_begin(ringbuf, 6);
+       if (ret)
+               return ret;
+
+       cmd = MI_STORE_DWORD_IMM_GEN8;
+       cmd |= MI_GLOBAL_GTT;
+
+       intel_logical_ring_emit(ringbuf, cmd);
+       intel_logical_ring_emit(ringbuf,
+                               (ring->status_page.gfx_addr +
+                               (I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT)));
+       intel_logical_ring_emit(ringbuf, 0);
+       intel_logical_ring_emit(ringbuf, ring->outstanding_lazy_seqno);
+       intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT);
+       intel_logical_ring_emit(ringbuf, MI_NOOP);
+       intel_logical_ring_advance_and_submit(ringbuf);
+
+       return 0;
+}
+
+/**
+ * intel_logical_ring_cleanup() - deallocate the Engine Command Streamer
+ *
+ * @ring: Engine Command Streamer.
+ *
+ */
+void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
+{
+       struct drm_i915_private *dev_priv = ring->dev->dev_private;
+
+       if (!intel_ring_initialized(ring))
+               return;
+
+       intel_logical_ring_stop(ring);
+       WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
+       ring->preallocated_lazy_request = NULL;
+       ring->outstanding_lazy_seqno = 0;
+
+       if (ring->cleanup)
+               ring->cleanup(ring);
+
+       i915_cmd_parser_fini_ring(ring);
+
+       if (ring->status_page.obj) {
+               kunmap(sg_page(ring->status_page.obj->pages->sgl));
+               ring->status_page.obj = NULL;
+       }
+}
+
+static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *ring)
+{
+       int ret;
+       struct intel_context *dctx = ring->default_context;
+       struct drm_i915_gem_object *dctx_obj;
+
+       /* Intentionally left blank. */
+       ring->buffer = NULL;
+
+       ring->dev = dev;
+       INIT_LIST_HEAD(&ring->active_list);
+       INIT_LIST_HEAD(&ring->request_list);
+       init_waitqueue_head(&ring->irq_queue);
+
+       INIT_LIST_HEAD(&ring->execlist_queue);
+       spin_lock_init(&ring->execlist_lock);
+       ring->next_context_status_buffer = 0;
+
+       ret = intel_lr_context_deferred_create(dctx, ring);
+       if (ret)
+               return ret;
+
+       /* The status page is offset 0 from the context object in LRCs. */
+       dctx_obj = dctx->engine[ring->id].state;
+       ring->status_page.gfx_addr = i915_gem_obj_ggtt_offset(dctx_obj);
+       ring->status_page.page_addr = kmap(sg_page(dctx_obj->pages->sgl));
+       if (ring->status_page.page_addr == NULL)
+               return -ENOMEM;
+       ring->status_page.obj = dctx_obj;
+
+       ret = i915_cmd_parser_init_ring(ring);
+       if (ret)
+               return ret;
+
+       if (ring->init) {
+               ret = ring->init(ring);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+static int logical_render_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[RCS];
+
+       ring->name = "render ring";
+       ring->id = RCS;
+       ring->mmio_base = RENDER_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_RCS_IRQ_SHIFT;
+       if (HAS_L3_DPF(dev))
+               ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
+
+       ring->init = gen8_init_render_ring;
+       ring->cleanup = intel_fini_pipe_control;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush_render;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+static int logical_bsd_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[VCS];
+
+       ring->name = "bsd ring";
+       ring->id = VCS;
+       ring->mmio_base = GEN6_BSD_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
+
+       ring->init = gen8_init_common_ring;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+static int logical_bsd2_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[VCS2];
+
+       ring->name = "bds2 ring";
+       ring->id = VCS2;
+       ring->mmio_base = GEN8_BSD2_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
+
+       ring->init = gen8_init_common_ring;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+static int logical_blt_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[BCS];
+
+       ring->name = "blitter ring";
+       ring->id = BCS;
+       ring->mmio_base = BLT_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+
+       ring->init = gen8_init_common_ring;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+static int logical_vebox_ring_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_engine_cs *ring = &dev_priv->ring[VECS];
+
+       ring->name = "video enhancement ring";
+       ring->id = VECS;
+       ring->mmio_base = VEBOX_RING_BASE;
+       ring->irq_enable_mask =
+               GT_RENDER_USER_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
+       ring->irq_keep_mask =
+               GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
+
+       ring->init = gen8_init_common_ring;
+       ring->get_seqno = gen8_get_seqno;
+       ring->set_seqno = gen8_set_seqno;
+       ring->emit_request = gen8_emit_request;
+       ring->emit_flush = gen8_emit_flush;
+       ring->irq_get = gen8_logical_ring_get_irq;
+       ring->irq_put = gen8_logical_ring_put_irq;
+       ring->emit_bb_start = gen8_emit_bb_start;
+
+       return logical_ring_init(dev, ring);
+}
+
+/**
+ * intel_logical_rings_init() - allocate, populate and init the Engine Command Streamers
+ * @dev: DRM device.
+ *
+ * This function inits the engines for an Execlists submission style (the equivalent in the
+ * legacy ringbuffer submission world would be i915_gem_init_rings). It does it only for
+ * those engines that are present in the hardware.
+ *
+ * Return: non-zero if the initialization failed.
+ */
+int intel_logical_rings_init(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
+
+       ret = logical_render_ring_init(dev);
+       if (ret)
+               return ret;
+
+       if (HAS_BSD(dev)) {
+               ret = logical_bsd_ring_init(dev);
+               if (ret)
+                       goto cleanup_render_ring;
+       }
+
+       if (HAS_BLT(dev)) {
+               ret = logical_blt_ring_init(dev);
+               if (ret)
+                       goto cleanup_bsd_ring;
+       }
+
+       if (HAS_VEBOX(dev)) {
+               ret = logical_vebox_ring_init(dev);
+               if (ret)
+                       goto cleanup_blt_ring;
+       }
+
+       if (HAS_BSD2(dev)) {
+               ret = logical_bsd2_ring_init(dev);
+               if (ret)
+                       goto cleanup_vebox_ring;
+       }
+
+       ret = i915_gem_set_seqno(dev, ((u32)~0 - 0x1000));
+       if (ret)
+               goto cleanup_bsd2_ring;
+
+       return 0;
+
+cleanup_bsd2_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[VCS2]);
+cleanup_vebox_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[VECS]);
+cleanup_blt_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[BCS]);
+cleanup_bsd_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[VCS]);
+cleanup_render_ring:
+       intel_logical_ring_cleanup(&dev_priv->ring[RCS]);
+
+       return ret;
+}
+
+static int
+populate_lr_context(struct intel_context *ctx, struct drm_i915_gem_object *ctx_obj,
+                   struct intel_engine_cs *ring, struct intel_ringbuffer *ringbuf)
+{
+       struct drm_i915_gem_object *ring_obj = ringbuf->obj;
+       struct i915_hw_ppgtt *ppgtt = ctx->ppgtt;
+       struct page *page;
+       uint32_t *reg_state;
+       int ret;
+
+       ret = i915_gem_object_set_to_cpu_domain(ctx_obj, true);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Could not set to CPU domain\n");
+               return ret;
+       }
+
+       ret = i915_gem_object_get_pages(ctx_obj);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Could not get object pages\n");
+               return ret;
+       }
+
+       i915_gem_object_pin_pages(ctx_obj);
+
+       /* The second page of the context object contains some fields which must
+        * be set up prior to the first execution. */
+       page = i915_gem_object_get_page(ctx_obj, 1);
+       reg_state = kmap_atomic(page);
+
+       /* A context is actually a big batch buffer with several MI_LOAD_REGISTER_IMM
+        * commands followed by (reg, value) pairs. The values we are setting here are
+        * only for the first context restore: on a subsequent save, the GPU will
+        * recreate this batchbuffer with new values (including all the missing
+        * MI_LOAD_REGISTER_IMM commands that we are not initializing here). */
+       if (ring->id == RCS)
+               reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(14);
+       else
+               reg_state[CTX_LRI_HEADER_0] = MI_LOAD_REGISTER_IMM(11);
+       reg_state[CTX_LRI_HEADER_0] |= MI_LRI_FORCE_POSTED;
+       reg_state[CTX_CONTEXT_CONTROL] = RING_CONTEXT_CONTROL(ring);
+       reg_state[CTX_CONTEXT_CONTROL+1] =
+                       _MASKED_BIT_ENABLE((1<<3) | MI_RESTORE_INHIBIT);
+       reg_state[CTX_RING_HEAD] = RING_HEAD(ring->mmio_base);
+       reg_state[CTX_RING_HEAD+1] = 0;
+       reg_state[CTX_RING_TAIL] = RING_TAIL(ring->mmio_base);
+       reg_state[CTX_RING_TAIL+1] = 0;
+       reg_state[CTX_RING_BUFFER_START] = RING_START(ring->mmio_base);
+       reg_state[CTX_RING_BUFFER_START+1] = i915_gem_obj_ggtt_offset(ring_obj);
+       reg_state[CTX_RING_BUFFER_CONTROL] = RING_CTL(ring->mmio_base);
+       reg_state[CTX_RING_BUFFER_CONTROL+1] =
+                       ((ringbuf->size - PAGE_SIZE) & RING_NR_PAGES) | RING_VALID;
+       reg_state[CTX_BB_HEAD_U] = ring->mmio_base + 0x168;
+       reg_state[CTX_BB_HEAD_U+1] = 0;
+       reg_state[CTX_BB_HEAD_L] = ring->mmio_base + 0x140;
+       reg_state[CTX_BB_HEAD_L+1] = 0;
+       reg_state[CTX_BB_STATE] = ring->mmio_base + 0x110;
+       reg_state[CTX_BB_STATE+1] = (1<<5);
+       reg_state[CTX_SECOND_BB_HEAD_U] = ring->mmio_base + 0x11c;
+       reg_state[CTX_SECOND_BB_HEAD_U+1] = 0;
+       reg_state[CTX_SECOND_BB_HEAD_L] = ring->mmio_base + 0x114;
+       reg_state[CTX_SECOND_BB_HEAD_L+1] = 0;
+       reg_state[CTX_SECOND_BB_STATE] = ring->mmio_base + 0x118;
+       reg_state[CTX_SECOND_BB_STATE+1] = 0;
+       if (ring->id == RCS) {
+               /* TODO: according to BSpec, the register state context
+                * for CHV does not have these. OTOH, these registers do
+                * exist in CHV. I'm waiting for a clarification */
+               reg_state[CTX_BB_PER_CTX_PTR] = ring->mmio_base + 0x1c0;
+               reg_state[CTX_BB_PER_CTX_PTR+1] = 0;
+               reg_state[CTX_RCS_INDIRECT_CTX] = ring->mmio_base + 0x1c4;
+               reg_state[CTX_RCS_INDIRECT_CTX+1] = 0;
+               reg_state[CTX_RCS_INDIRECT_CTX_OFFSET] = ring->mmio_base + 0x1c8;
+               reg_state[CTX_RCS_INDIRECT_CTX_OFFSET+1] = 0;
+       }
+       reg_state[CTX_LRI_HEADER_1] = MI_LOAD_REGISTER_IMM(9);
+       reg_state[CTX_LRI_HEADER_1] |= MI_LRI_FORCE_POSTED;
+       reg_state[CTX_CTX_TIMESTAMP] = ring->mmio_base + 0x3a8;
+       reg_state[CTX_CTX_TIMESTAMP+1] = 0;
+       reg_state[CTX_PDP3_UDW] = GEN8_RING_PDP_UDW(ring, 3);
+       reg_state[CTX_PDP3_LDW] = GEN8_RING_PDP_LDW(ring, 3);
+       reg_state[CTX_PDP2_UDW] = GEN8_RING_PDP_UDW(ring, 2);
+       reg_state[CTX_PDP2_LDW] = GEN8_RING_PDP_LDW(ring, 2);
+       reg_state[CTX_PDP1_UDW] = GEN8_RING_PDP_UDW(ring, 1);
+       reg_state[CTX_PDP1_LDW] = GEN8_RING_PDP_LDW(ring, 1);
+       reg_state[CTX_PDP0_UDW] = GEN8_RING_PDP_UDW(ring, 0);
+       reg_state[CTX_PDP0_LDW] = GEN8_RING_PDP_LDW(ring, 0);
+       reg_state[CTX_PDP3_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[3]);
+       reg_state[CTX_PDP3_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[3]);
+       reg_state[CTX_PDP2_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[2]);
+       reg_state[CTX_PDP2_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[2]);
+       reg_state[CTX_PDP1_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[1]);
+       reg_state[CTX_PDP1_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[1]);
+       reg_state[CTX_PDP0_UDW+1] = upper_32_bits(ppgtt->pd_dma_addr[0]);
+       reg_state[CTX_PDP0_LDW+1] = lower_32_bits(ppgtt->pd_dma_addr[0]);
+       if (ring->id == RCS) {
+               reg_state[CTX_LRI_HEADER_2] = MI_LOAD_REGISTER_IMM(1);
+               reg_state[CTX_R_PWR_CLK_STATE] = 0x20c8;
+               reg_state[CTX_R_PWR_CLK_STATE+1] = 0;
+       }
+
+       kunmap_atomic(reg_state);
+
+       ctx_obj->dirty = 1;
+       set_page_dirty(page);
+       i915_gem_object_unpin_pages(ctx_obj);
+
+       return 0;
+}
+
+/**
+ * intel_lr_context_free() - free the LRC specific bits of a context
+ * @ctx: the LR context to free.
+ *
+ * The real context freeing is done in i915_gem_context_free: this only
+ * takes care of the bits that are LRC related: the per-engine backing
+ * objects and the logical ringbuffer.
+ */
+void intel_lr_context_free(struct intel_context *ctx)
+{
+       int i;
+
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct drm_i915_gem_object *ctx_obj = ctx->engine[i].state;
+               struct intel_ringbuffer *ringbuf = ctx->engine[i].ringbuf;
+
+               if (ctx_obj) {
+                       intel_destroy_ringbuffer_obj(ringbuf);
+                       kfree(ringbuf);
+                       i915_gem_object_ggtt_unpin(ctx_obj);
+                       drm_gem_object_unreference(&ctx_obj->base);
+               }
+       }
+}
+
+static uint32_t get_lr_context_size(struct intel_engine_cs *ring)
+{
+       int ret = 0;
+
+       WARN_ON(INTEL_INFO(ring->dev)->gen != 8);
+
+       switch (ring->id) {
+       case RCS:
+               ret = GEN8_LR_CONTEXT_RENDER_SIZE;
+               break;
+       case VCS:
+       case BCS:
+       case VECS:
+       case VCS2:
+               ret = GEN8_LR_CONTEXT_OTHER_SIZE;
+               break;
+       }
+
+       return ret;
+}
+
+/**
+ * intel_lr_context_deferred_create() - create the LRC specific bits of a context
+ * @ctx: LR context to create.
+ * @ring: engine to be used with the context.
+ *
+ * This function can be called more than once, with different engines, if we plan
+ * to use the context with them. The context backing objects and the ringbuffers
+ * (specially the ringbuffer backing objects) suck a lot of memory up, and that's why
+ * the creation is a deferred call: it's better to make sure first that we need to use
+ * a given ring with the context.
+ *
+ * Return: non-zero on eror.
+ */
+int intel_lr_context_deferred_create(struct intel_context *ctx,
+                                    struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+       struct drm_i915_gem_object *ctx_obj;
+       uint32_t context_size;
+       struct intel_ringbuffer *ringbuf;
+       int ret;
+
+       WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL);
+       if (ctx->engine[ring->id].state)
+               return 0;
+
+       context_size = round_up(get_lr_context_size(ring), 4096);
+
+       ctx_obj = i915_gem_alloc_context_obj(dev, context_size);
+       if (IS_ERR(ctx_obj)) {
+               ret = PTR_ERR(ctx_obj);
+               DRM_DEBUG_DRIVER("Alloc LRC backing obj failed: %d\n", ret);
+               return ret;
+       }
+
+       ret = i915_gem_obj_ggtt_pin(ctx_obj, GEN8_LR_CONTEXT_ALIGN, 0);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Pin LRC backing obj failed: %d\n", ret);
+               drm_gem_object_unreference(&ctx_obj->base);
+               return ret;
+       }
+
+       ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
+       if (!ringbuf) {
+               DRM_DEBUG_DRIVER("Failed to allocate ringbuffer %s\n",
+                               ring->name);
+               i915_gem_object_ggtt_unpin(ctx_obj);
+               drm_gem_object_unreference(&ctx_obj->base);
+               ret = -ENOMEM;
+               return ret;
+       }
+
+       ringbuf->ring = ring;
+       ringbuf->FIXME_lrc_ctx = ctx;
+
+       ringbuf->size = 32 * PAGE_SIZE;
+       ringbuf->effective_size = ringbuf->size;
+       ringbuf->head = 0;
+       ringbuf->tail = 0;
+       ringbuf->space = ringbuf->size;
+       ringbuf->last_retired_head = -1;
+
+       /* TODO: For now we put this in the mappable region so that we can reuse
+        * the existing ringbuffer code which ioremaps it. When we start
+        * creating many contexts, this will no longer work and we must switch
+        * to a kmapish interface.
+        */
+       ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Failed to allocate ringbuffer obj %s: %d\n",
+                               ring->name, ret);
+               goto error;
+       }
+
+       ret = populate_lr_context(ctx, ctx_obj, ring, ringbuf);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Failed to populate LRC: %d\n", ret);
+               intel_destroy_ringbuffer_obj(ringbuf);
+               goto error;
+       }
+
+       ctx->engine[ring->id].ringbuf = ringbuf;
+       ctx->engine[ring->id].state = ctx_obj;
+
+       return 0;
+
+error:
+       kfree(ringbuf);
+       i915_gem_object_ggtt_unpin(ctx_obj);
+       drm_gem_object_unreference(&ctx_obj->base);
+       return ret;
+}
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
new file mode 100644 (file)
index 0000000..991d449
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright Â© 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef _INTEL_LRC_H_
+#define _INTEL_LRC_H_
+
+/* Execlists regs */
+#define RING_ELSP(ring)                        ((ring)->mmio_base+0x230)
+#define RING_EXECLIST_STATUS(ring)     ((ring)->mmio_base+0x234)
+#define RING_CONTEXT_CONTROL(ring)     ((ring)->mmio_base+0x244)
+#define RING_CONTEXT_STATUS_BUF(ring)  ((ring)->mmio_base+0x370)
+#define RING_CONTEXT_STATUS_PTR(ring)  ((ring)->mmio_base+0x3a0)
+
+/* Logical Rings */
+void intel_logical_ring_stop(struct intel_engine_cs *ring);
+void intel_logical_ring_cleanup(struct intel_engine_cs *ring);
+int intel_logical_rings_init(struct drm_device *dev);
+
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf);
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf);
+/**
+ * intel_logical_ring_advance() - advance the ringbuffer tail
+ * @ringbuf: Ringbuffer to advance.
+ *
+ * The tail is only updated in our logical ringbuffer struct.
+ */
+static inline void intel_logical_ring_advance(struct intel_ringbuffer *ringbuf)
+{
+       ringbuf->tail &= ringbuf->size - 1;
+}
+/**
+ * intel_logical_ring_emit() - write a DWORD to the ringbuffer.
+ * @ringbuf: Ringbuffer to write to.
+ * @data: DWORD to write.
+ */
+static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
+                                          u32 data)
+{
+       iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
+       ringbuf->tail += 4;
+}
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
+
+/* Logical Ring Contexts */
+void intel_lr_context_free(struct intel_context *ctx);
+int intel_lr_context_deferred_create(struct intel_context *ctx,
+                                    struct intel_engine_cs *ring);
+
+/* Execlists */
+int intel_sanitize_enable_execlists(struct drm_device *dev, int enable_execlists);
+int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
+                              struct intel_engine_cs *ring,
+                              struct intel_context *ctx,
+                              struct drm_i915_gem_execbuffer2 *args,
+                              struct list_head *vmas,
+                              struct drm_i915_gem_object *batch_obj,
+                              u64 exec_start, u32 flags);
+u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
+
+/**
+ * struct intel_ctx_submit_request - queued context submission request
+ * @ctx: Context to submit to the ELSP.
+ * @ring: Engine to submit it to.
+ * @tail: how far in the context's ringbuffer this request goes to.
+ * @execlist_link: link in the submission queue.
+ * @work: workqueue for processing this request in a bottom half.
+ * @elsp_submitted: no. of times this request has been sent to the ELSP.
+ *
+ * The ELSP only accepts two elements at a time, so we queue context/tail
+ * pairs on a given queue (ring->execlist_queue) until the hardware is
+ * available. The queue serves a double purpose: we also use it to keep track
+ * of the up to 2 contexts currently in the hardware (usually one in execution
+ * and the other queued up by the GPU): We only remove elements from the head
+ * of the queue when the hardware informs us that an element has been
+ * completed.
+ *
+ * All accesses to the queue are mediated by a spinlock (ring->execlist_lock).
+ */
+struct intel_ctx_submit_request {
+       struct intel_context *ctx;
+       struct intel_engine_cs *ring;
+       u32 tail;
+
+       struct list_head execlist_link;
+       struct work_struct work;
+
+       int elsp_submitted;
+};
+
+void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
+
+#endif /* _INTEL_LRC_H_ */
index 020e9ab567ed93d7caa261b2dc6bac3e0af52dcd..c8f744c418f0082ef0c7eeea12c3323e83e03e60 100644 (file)
@@ -3719,7 +3719,6 @@ static void gen6_enable_rps(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_engine_cs *ring;
        u32 rp_state_cap;
-       u32 gt_perf_status;
        u32 rc6vids, pcu_mbox = 0, rc6_mask = 0;
        u32 gtfifodbg;
        int rc6_mode;
@@ -3744,7 +3743,6 @@ static void gen6_enable_rps(struct drm_device *dev)
        gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
        rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
-       gt_perf_status = I915_READ(GEN6_GT_PERF_STATUS);
 
        parse_rp_state_cap(dev_priv, rp_state_cap);
 
index 117543e58d4889a74469a169efb65f94df0ef9da..4fb1ec95ec08ef9161eb5146b9d4661fe309933d 100644 (file)
 #include "i915_trace.h"
 #include "intel_drv.h"
 
-/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill,
- * but keeps the logic simple. Indeed, the whole purpose of this macro is just
- * to give some inclination as to some of the magic values used in the various
- * workarounds!
- */
-#define CACHELINE_BYTES 64
+bool
+intel_ring_initialized(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+
+       if (!dev)
+               return false;
 
-static inline int __ring_space(int head, int tail, int size)
+       if (i915.enable_execlists) {
+               struct intel_context *dctx = ring->default_context;
+               struct intel_ringbuffer *ringbuf = dctx->engine[ring->id].ringbuf;
+
+               return ringbuf->obj;
+       } else
+               return ring->buffer && ring->buffer->obj;
+}
+
+int __intel_ring_space(int head, int tail, int size)
 {
        int space = head - (tail + I915_RING_FREE_SPACE);
        if (space < 0)
@@ -48,12 +58,13 @@ static inline int __ring_space(int head, int tail, int size)
        return space;
 }
 
-static inline int ring_space(struct intel_ringbuffer *ringbuf)
+int intel_ring_space(struct intel_ringbuffer *ringbuf)
 {
-       return __ring_space(ringbuf->head & HEAD_ADDR, ringbuf->tail, ringbuf->size);
+       return __intel_ring_space(ringbuf->head & HEAD_ADDR,
+                                 ringbuf->tail, ringbuf->size);
 }
 
-static bool intel_ring_stopped(struct intel_engine_cs *ring)
+bool intel_ring_stopped(struct intel_engine_cs *ring)
 {
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        return dev_priv->gpu_error.stop_rings & intel_ring_flag(ring);
@@ -478,7 +489,12 @@ static bool stop_ring(struct intel_engine_cs *ring)
                I915_WRITE_MODE(ring, _MASKED_BIT_ENABLE(STOP_RING));
                if (wait_for((I915_READ_MODE(ring) & MODE_IDLE) != 0, 1000)) {
                        DRM_ERROR("%s : timed out trying to stop ring\n", ring->name);
-                       return false;
+                       /* Sometimes we observe that the idle flag is not
+                        * set even though the ring is empty. So double
+                        * check before giving up.
+                        */
+                       if (I915_READ_HEAD(ring) != I915_READ_TAIL(ring))
+                               return false;
                }
        }
 
@@ -563,7 +579,7 @@ static int init_ring_common(struct intel_engine_cs *ring)
        else {
                ringbuf->head = I915_READ_HEAD(ring);
                ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
-               ringbuf->space = ring_space(ringbuf);
+               ringbuf->space = intel_ring_space(ringbuf);
                ringbuf->last_retired_head = -1;
        }
 
@@ -575,8 +591,25 @@ out:
        return ret;
 }
 
-static int
-init_pipe_control(struct intel_engine_cs *ring)
+void
+intel_fini_pipe_control(struct intel_engine_cs *ring)
+{
+       struct drm_device *dev = ring->dev;
+
+       if (ring->scratch.obj == NULL)
+               return;
+
+       if (INTEL_INFO(dev)->gen >= 5) {
+               kunmap(sg_page(ring->scratch.obj->pages->sgl));
+               i915_gem_object_ggtt_unpin(ring->scratch.obj);
+       }
+
+       drm_gem_object_unreference(&ring->scratch.obj->base);
+       ring->scratch.obj = NULL;
+}
+
+int
+intel_init_pipe_control(struct intel_engine_cs *ring)
 {
        int ret;
 
@@ -651,7 +684,7 @@ static int init_render_ring(struct intel_engine_cs *ring)
                           _MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
 
        if (INTEL_INFO(dev)->gen >= 5) {
-               ret = init_pipe_control(ring);
+               ret = intel_init_pipe_control(ring);
                if (ret)
                        return ret;
        }
@@ -686,16 +719,7 @@ static void render_ring_cleanup(struct intel_engine_cs *ring)
                dev_priv->semaphore_obj = NULL;
        }
 
-       if (ring->scratch.obj == NULL)
-               return;
-
-       if (INTEL_INFO(dev)->gen >= 5) {
-               kunmap(sg_page(ring->scratch.obj->pages->sgl));
-               i915_gem_object_ggtt_unpin(ring->scratch.obj);
-       }
-
-       drm_gem_object_unreference(&ring->scratch.obj->base);
-       ring->scratch.obj = NULL;
+       intel_fini_pipe_control(ring);
 }
 
 static int gen8_rcs_signal(struct intel_engine_cs *signaller,
@@ -1514,7 +1538,7 @@ static int init_phys_status_page(struct intel_engine_cs *ring)
        return 0;
 }
 
-static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
+void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
 {
        if (!ringbuf->obj)
                return;
@@ -1525,8 +1549,8 @@ static void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf)
        ringbuf->obj = NULL;
 }
 
-static int intel_alloc_ringbuffer_obj(struct drm_device *dev,
-                                     struct intel_ringbuffer *ringbuf)
+int intel_alloc_ringbuffer_obj(struct drm_device *dev,
+                              struct intel_ringbuffer *ringbuf)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct drm_i915_gem_object *obj;
@@ -1588,7 +1612,9 @@ static int intel_init_ring_buffer(struct drm_device *dev,
        ring->dev = dev;
        INIT_LIST_HEAD(&ring->active_list);
        INIT_LIST_HEAD(&ring->request_list);
+       INIT_LIST_HEAD(&ring->execlist_queue);
        ringbuf->size = 32 * PAGE_SIZE;
+       ringbuf->ring = ring;
        memset(ring->semaphore.sync_seqno, 0, sizeof(ring->semaphore.sync_seqno));
 
        init_waitqueue_head(&ring->irq_queue);
@@ -1671,13 +1697,14 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
                ringbuf->head = ringbuf->last_retired_head;
                ringbuf->last_retired_head = -1;
 
-               ringbuf->space = ring_space(ringbuf);
+               ringbuf->space = intel_ring_space(ringbuf);
                if (ringbuf->space >= n)
                        return 0;
        }
 
        list_for_each_entry(request, &ring->request_list, list) {
-               if (__ring_space(request->tail, ringbuf->tail, ringbuf->size) >= n) {
+               if (__intel_ring_space(request->tail, ringbuf->tail,
+                                      ringbuf->size) >= n) {
                        seqno = request->seqno;
                        break;
                }
@@ -1694,7 +1721,7 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
        ringbuf->head = ringbuf->last_retired_head;
        ringbuf->last_retired_head = -1;
 
-       ringbuf->space = ring_space(ringbuf);
+       ringbuf->space = intel_ring_space(ringbuf);
        return 0;
 }
 
@@ -1723,7 +1750,7 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n)
        trace_i915_ring_wait_begin(ring);
        do {
                ringbuf->head = I915_READ_HEAD(ring);
-               ringbuf->space = ring_space(ringbuf);
+               ringbuf->space = intel_ring_space(ringbuf);
                if (ringbuf->space >= n) {
                        ret = 0;
                        break;
@@ -1775,7 +1802,7 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring)
                iowrite32(MI_NOOP, virt++);
 
        ringbuf->tail = 0;
-       ringbuf->space = ring_space(ringbuf);
+       ringbuf->space = intel_ring_space(ringbuf);
 
        return 0;
 }
@@ -1980,9 +2007,7 @@ gen8_ring_dispatch_execbuffer(struct intel_engine_cs *ring,
                              u64 offset, u32 len,
                              unsigned flags)
 {
-       struct drm_i915_private *dev_priv = ring->dev->dev_private;
-       bool ppgtt = dev_priv->mm.aliasing_ppgtt != NULL &&
-               !(flags & I915_DISPATCH_SECURE);
+       bool ppgtt = USES_PPGTT(ring->dev) && !(flags & I915_DISPATCH_SECURE);
        int ret;
 
        ret = intel_ring_begin(ring, 4);
index 70525d0c2c74650ef780a69c797c59316cedd371..9cbf7b0ebc994fd6bd383fcb112d9b4413c1932f 100644 (file)
@@ -5,6 +5,13 @@
 
 #define I915_CMD_HASH_ORDER 9
 
+/* Early gen2 devices have a cacheline of just 32 bytes, using 64 is overkill,
+ * but keeps the logic simple. Indeed, the whole purpose of this macro is just
+ * to give some inclination as to some of the magic values used in the various
+ * workarounds!
+ */
+#define CACHELINE_BYTES 64
+
 /*
  * Gen2 BSpec "1. Programming Environment" / 1.4.4.6 "Ring Buffer Use"
  * Gen3 BSpec "vol1c Memory Interface Functions" / 2.3.4.5 "Ring Buffer Use"
@@ -90,6 +97,15 @@ struct intel_ringbuffer {
        struct drm_i915_gem_object *obj;
        void __iomem *virtual_start;
 
+       struct intel_engine_cs *ring;
+
+       /*
+        * FIXME: This backpointer is an artifact of the history of how the
+        * execlist patches came into being. It will get removed once the basic
+        * code has landed.
+        */
+       struct intel_context *FIXME_lrc_ctx;
+
        u32 head;
        u32 tail;
        int space;
@@ -214,6 +230,18 @@ struct  intel_engine_cs {
                                  unsigned int num_dwords);
        } semaphore;
 
+       /* Execlists */
+       spinlock_t execlist_lock;
+       struct list_head execlist_queue;
+       u8 next_context_status_buffer;
+       u32             irq_keep_mask; /* bitmask for interrupts that should not be masked */
+       int             (*emit_request)(struct intel_ringbuffer *ringbuf);
+       int             (*emit_flush)(struct intel_ringbuffer *ringbuf,
+                                     u32 invalidate_domains,
+                                     u32 flush_domains);
+       int             (*emit_bb_start)(struct intel_ringbuffer *ringbuf,
+                                        u64 offset, unsigned flags);
+
        /**
         * List of objects currently involved in rendering from the
         * ringbuffer.
@@ -287,11 +315,7 @@ struct  intel_engine_cs {
        u32 (*get_cmd_length_mask)(u32 cmd_header);
 };
 
-static inline bool
-intel_ring_initialized(struct intel_engine_cs *ring)
-{
-       return ring->buffer && ring->buffer->obj;
-}
+bool intel_ring_initialized(struct intel_engine_cs *ring);
 
 static inline unsigned
 intel_ring_flag(struct intel_engine_cs *ring)
@@ -355,6 +379,10 @@ intel_write_status_page(struct intel_engine_cs *ring,
 #define I915_GEM_HWS_SCRATCH_INDEX     0x30
 #define I915_GEM_HWS_SCRATCH_ADDR (I915_GEM_HWS_SCRATCH_INDEX << MI_STORE_DWORD_INDEX_SHIFT)
 
+void intel_destroy_ringbuffer_obj(struct intel_ringbuffer *ringbuf);
+int intel_alloc_ringbuffer_obj(struct drm_device *dev,
+                              struct intel_ringbuffer *ringbuf);
+
 void intel_stop_ring_buffer(struct intel_engine_cs *ring);
 void intel_cleanup_ring_buffer(struct intel_engine_cs *ring);
 
@@ -372,6 +400,9 @@ static inline void intel_ring_advance(struct intel_engine_cs *ring)
        struct intel_ringbuffer *ringbuf = ring->buffer;
        ringbuf->tail &= ringbuf->size - 1;
 }
+int __intel_ring_space(int head, int tail, int size);
+int intel_ring_space(struct intel_ringbuffer *ringbuf);
+bool intel_ring_stopped(struct intel_engine_cs *ring);
 void __intel_ring_advance(struct intel_engine_cs *ring);
 
 int __must_check intel_ring_idle(struct intel_engine_cs *ring);
@@ -379,6 +410,9 @@ void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno);
 int intel_ring_flush_all_caches(struct intel_engine_cs *ring);
 int intel_ring_invalidate_all_caches(struct intel_engine_cs *ring);
 
+void intel_fini_pipe_control(struct intel_engine_cs *ring);
+int intel_init_pipe_control(struct intel_engine_cs *ring);
+
 int intel_init_render_ring_buffer(struct drm_device *dev);
 int intel_init_bsd_ring_buffer(struct drm_device *dev);
 int intel_init_bsd2_ring_buffer(struct drm_device *dev);
index 0375d75552f18275e31ffc67225f8c91a4d321dd..31344bf7887ee53a5c057c63051f74653569fd90 100644 (file)
@@ -1127,6 +1127,9 @@ extern int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
                                             struct drm_file *file_priv);
 extern int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
                                           struct drm_file *file_priv);
+extern int drm_mode_plane_set_obj_prop(struct drm_plane *plane,
+                                      struct drm_property *property,
+                                      uint64_t value);
 
 extern void drm_fb_get_bpp_depth(uint32_t format, unsigned int *depth,
                                 int *bpp);