drm/i915: Do remaps for all contexts
authorBen Widawsky <benjamin.widawsky@intel.com>
Thu, 19 Sep 2013 02:03:18 +0000 (19:03 -0700)
committerDaniel Vetter <daniel.vetter@ffwll.ch>
Thu, 19 Sep 2013 18:39:56 +0000 (20:39 +0200)
On both Ivybridge and Haswell, row remapping information is saved and
restored with context. This means, we never actually properly supported
the l3 remapping because our sysfs interface is asynchronous (and not
tied to any context), and the known faulty HW would be reused by the
next context to run.

Not that due to the asynchronous nature of the sysfs entry, there is no
point modifying the registers for the existing context. Instead we set a
flag for all contexts to load the correct remapping information on the
next run. Interested clients can use debugfs to determine whether or not
the row has been remapped.

One could propose at this point that we just do the remapping in the
kernel. I guess since we have to maintain the sysfs interface anyway,
I'm not sure how useful it is, and I do like keeping the policy in
userspace; (it wasn't my original decision to make the
interface the way it is, so I'm not attached).

v2: Force a context switch when we have a remap on the next switch.
(Ville)
Don't let userspace use the interface with disabled contexts.

v3: Don't force a context switch, just let it nop
Improper context slice remap initialization, 1<<1 instead of 1<<i, but I
rewrote it to avoid a second round of confusion.
Error print moved to error path (All Ville)
Added a comment on why the slice remap initialization happens.

CC: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Ben Widawsky <ben@bwidawsk.net>
Reviewed-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
drivers/gpu/drm/i915/i915_debugfs.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem_context.c
drivers/gpu/drm/i915/i915_sysfs.c

index ada095023dad20061609909c7724b309a66a25fc..80bed69fe5b7436c6ae7496d312c0101651b274d 100644 (file)
@@ -145,6 +145,13 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
                seq_printf(m, " (%s)", obj->ring->name);
 }
 
+static void describe_ctx(struct seq_file *m, struct i915_hw_context *ctx)
+{
+       seq_putc(m, ctx->is_initialized ? 'I' : 'i');
+       seq_putc(m, ctx->remap_slice ? 'R' : 'r');
+       seq_putc(m, ' ');
+}
+
 static int i915_gem_object_list_info(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
@@ -1463,6 +1470,7 @@ static int i915_context_status(struct seq_file *m, void *unused)
 
        list_for_each_entry(ctx, &dev_priv->context_list, link) {
                seq_puts(m, "HW context ");
+               describe_ctx(m, ctx);
                for_each_ring(ring, dev_priv, i)
                        if (ring->default_context == ctx)
                                seq_printf(m, "(default context %s) ", ring->name);
index 179592762537ca861f0911650e1783007730ade5..015df5264dcc6c53a0429997669a1da75060d055 100644 (file)
@@ -601,6 +601,7 @@ struct i915_hw_context {
        struct kref ref;
        int id;
        bool is_initialized;
+       uint8_t remap_slice;
        struct drm_i915_file_private *file_priv;
        struct intel_ring_buffer *ring;
        struct drm_i915_gem_object *obj;
index 2bbdce821ac380b46d468b060d00fd90c2aebb07..9af3fe7e42b0297608eddca5cc335666719bf8ce 100644 (file)
@@ -181,6 +181,10 @@ create_hw_context(struct drm_device *dev,
 
        ctx->file_priv = file_priv;
        ctx->id = ret;
+       /* NB: Mark all slices as needing a remap so that when the context first
+        * loads it will restore whatever remap state already exists. If there
+        * is no remap info, it will be a NOP. */
+       ctx->remap_slice = (1 << NUM_L3_SLICES(dev)) - 1;
 
        return ctx;
 
@@ -396,11 +400,11 @@ static int do_switch(struct i915_hw_context *to)
        struct intel_ring_buffer *ring = to->ring;
        struct i915_hw_context *from = ring->last_context;
        u32 hw_flags = 0;
-       int ret;
+       int ret, i;
 
        BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0);
 
-       if (from == to)
+       if (from == to && !to->remap_slice)
                return 0;
 
        ret = i915_gem_obj_ggtt_pin(to->obj, CONTEXT_ALIGN, false, false);
@@ -423,8 +427,6 @@ static int do_switch(struct i915_hw_context *to)
 
        if (!to->is_initialized || is_default_context(to))
                hw_flags |= MI_RESTORE_INHIBIT;
-       else if (WARN_ON_ONCE(from == to)) /* not yet expected */
-               hw_flags |= MI_FORCE_RESTORE;
 
        ret = mi_set_context(ring, to, hw_flags);
        if (ret) {
@@ -432,6 +434,18 @@ static int do_switch(struct i915_hw_context *to)
                return ret;
        }
 
+       for (i = 0; i < MAX_L3_SLICES; i++) {
+               if (!(to->remap_slice & (1<<i)))
+                       continue;
+
+               ret = i915_gem_l3_remap(ring, i);
+               /* If it failed, try again next round */
+               if (ret)
+                       DRM_DEBUG_DRIVER("L3 remapping failed\n");
+               else
+                       to->remap_slice &= ~(1<<i);
+       }
+
        /* The backing object for the context is done after switching to the
         * *next* context. Therefore we cannot retire the previous context until
         * the next context has already started running. In fact, the below code
index b07bdfb8892d87037f46ad9197d84e93cf0c4f1d..deb8787308d6f4a959c1c32bd6e7f340c6a27f62 100644 (file)
@@ -118,9 +118,8 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
        struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
        struct drm_device *drm_dev = dminor->dev;
        struct drm_i915_private *dev_priv = drm_dev->dev_private;
-       uint32_t misccpctl;
        int slice = (int)(uintptr_t)attr->private;
-       int i, ret;
+       int ret;
 
        count = round_down(count, 4);
 
@@ -134,26 +133,13 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
        if (ret)
                return ret;
 
-       if (IS_HASWELL(drm_dev)) {
-               if (dev_priv->l3_parity.remap_info[slice])
-                       memcpy(buf,
-                              dev_priv->l3_parity.remap_info[slice] + (offset/4),
-                              count);
-               else
-                       memset(buf, 0, count);
-
-               goto out;
-       }
-
-       misccpctl = I915_READ(GEN7_MISCCPCTL);
-       I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
-
-       for (i = 0; i < count; i += 4)
-               *((uint32_t *)(&buf[i])) = I915_READ(GEN7_L3LOG_BASE + offset + i);
-
-       I915_WRITE(GEN7_MISCCPCTL, misccpctl);
+       if (dev_priv->l3_parity.remap_info[slice])
+               memcpy(buf,
+                      dev_priv->l3_parity.remap_info[slice] + (offset/4),
+                      count);
+       else
+               memset(buf, 0, count);
 
-out:
        mutex_unlock(&drm_dev->struct_mutex);
 
        return count;
@@ -168,6 +154,7 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
        struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
        struct drm_device *drm_dev = dminor->dev;
        struct drm_i915_private *dev_priv = drm_dev->dev_private;
+       struct i915_hw_context *ctx;
        u32 *temp = NULL; /* Just here to make handling failures easy */
        int slice = (int)(uintptr_t)attr->private;
        int ret;
@@ -176,6 +163,9 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
        if (ret)
                return ret;
 
+       if (dev_priv->hw_contexts_disabled)
+               return -ENXIO;
+
        ret = i915_mutex_lock_interruptible(drm_dev);
        if (ret)
                return ret;
@@ -204,8 +194,9 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
 
        memcpy(dev_priv->l3_parity.remap_info[slice] + (offset/4), buf, count);
 
-       if (i915_gem_l3_remap(&dev_priv->ring[RCS], slice))
-               count = 0;
+       /* NB: We defer the remapping until we switch to the context */
+       list_for_each_entry(ctx, &dev_priv->context_list, link)
+               ctx->remap_slice |= (1<<slice);
 
        mutex_unlock(&drm_dev->struct_mutex);
 
This page took 0.032798 seconds and 5 git commands to generate.