aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBen Widawsky <benjamin.widawsky@intel.com>2013-09-18 22:03:18 -0400
committerDaniel Vetter <daniel.vetter@ffwll.ch>2013-09-19 14:39:56 -0400
commit3ccfd19dea7c5c85aa4b1f929a97a02b026ab356 (patch)
tree35244a599b81e7887a6211b8a5afca2f2eb98ce1 /drivers
parenta33afea5ff6e5b87ac11c87fb60b3704b3ac0fcc (diff)
drm/i915: Do remaps for all contexts
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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c8
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h1
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c22
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c37
4 files changed, 41 insertions, 27 deletions
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index ada095023dad..80bed69fe5b7 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -145,6 +145,13 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
145 seq_printf(m, " (%s)", obj->ring->name); 145 seq_printf(m, " (%s)", obj->ring->name);
146} 146}
147 147
148static void describe_ctx(struct seq_file *m, struct i915_hw_context *ctx)
149{
150 seq_putc(m, ctx->is_initialized ? 'I' : 'i');
151 seq_putc(m, ctx->remap_slice ? 'R' : 'r');
152 seq_putc(m, ' ');
153}
154
148static int i915_gem_object_list_info(struct seq_file *m, void *data) 155static int i915_gem_object_list_info(struct seq_file *m, void *data)
149{ 156{
150 struct drm_info_node *node = (struct drm_info_node *) m->private; 157 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)
1463 1470
1464 list_for_each_entry(ctx, &dev_priv->context_list, link) { 1471 list_for_each_entry(ctx, &dev_priv->context_list, link) {
1465 seq_puts(m, "HW context "); 1472 seq_puts(m, "HW context ");
1473 describe_ctx(m, ctx);
1466 for_each_ring(ring, dev_priv, i) 1474 for_each_ring(ring, dev_priv, i)
1467 if (ring->default_context == ctx) 1475 if (ring->default_context == ctx)
1468 seq_printf(m, "(default context %s) ", ring->name); 1476 seq_printf(m, "(default context %s) ", ring->name);
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 179592762537..015df5264dcc 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -601,6 +601,7 @@ struct i915_hw_context {
601 struct kref ref; 601 struct kref ref;
602 int id; 602 int id;
603 bool is_initialized; 603 bool is_initialized;
604 uint8_t remap_slice;
604 struct drm_i915_file_private *file_priv; 605 struct drm_i915_file_private *file_priv;
605 struct intel_ring_buffer *ring; 606 struct intel_ring_buffer *ring;
606 struct drm_i915_gem_object *obj; 607 struct drm_i915_gem_object *obj;
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index 2bbdce821ac3..9af3fe7e42b0 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -181,6 +181,10 @@ create_hw_context(struct drm_device *dev,
181 181
182 ctx->file_priv = file_priv; 182 ctx->file_priv = file_priv;
183 ctx->id = ret; 183 ctx->id = ret;
184 /* NB: Mark all slices as needing a remap so that when the context first
185 * loads it will restore whatever remap state already exists. If there
186 * is no remap info, it will be a NOP. */
187 ctx->remap_slice = (1 << NUM_L3_SLICES(dev)) - 1;
184 188
185 return ctx; 189 return ctx;
186 190
@@ -396,11 +400,11 @@ static int do_switch(struct i915_hw_context *to)
396 struct intel_ring_buffer *ring = to->ring; 400 struct intel_ring_buffer *ring = to->ring;
397 struct i915_hw_context *from = ring->last_context; 401 struct i915_hw_context *from = ring->last_context;
398 u32 hw_flags = 0; 402 u32 hw_flags = 0;
399 int ret; 403 int ret, i;
400 404
401 BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0); 405 BUG_ON(from != NULL && from->obj != NULL && from->obj->pin_count == 0);
402 406
403 if (from == to) 407 if (from == to && !to->remap_slice)
404 return 0; 408 return 0;
405 409
406 ret = i915_gem_obj_ggtt_pin(to->obj, CONTEXT_ALIGN, false, false); 410 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)
423 427
424 if (!to->is_initialized || is_default_context(to)) 428 if (!to->is_initialized || is_default_context(to))
425 hw_flags |= MI_RESTORE_INHIBIT; 429 hw_flags |= MI_RESTORE_INHIBIT;
426 else if (WARN_ON_ONCE(from == to)) /* not yet expected */
427 hw_flags |= MI_FORCE_RESTORE;
428 430
429 ret = mi_set_context(ring, to, hw_flags); 431 ret = mi_set_context(ring, to, hw_flags);
430 if (ret) { 432 if (ret) {
@@ -432,6 +434,18 @@ static int do_switch(struct i915_hw_context *to)
432 return ret; 434 return ret;
433 } 435 }
434 436
437 for (i = 0; i < MAX_L3_SLICES; i++) {
438 if (!(to->remap_slice & (1<<i)))
439 continue;
440
441 ret = i915_gem_l3_remap(ring, i);
442 /* If it failed, try again next round */
443 if (ret)
444 DRM_DEBUG_DRIVER("L3 remapping failed\n");
445 else
446 to->remap_slice &= ~(1<<i);
447 }
448
435 /* The backing object for the context is done after switching to the 449 /* The backing object for the context is done after switching to the
436 * *next* context. Therefore we cannot retire the previous context until 450 * *next* context. Therefore we cannot retire the previous context until
437 * the next context has already started running. In fact, the below code 451 * the next context has already started running. In fact, the below code
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index b07bdfb8892d..deb8787308d6 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -118,9 +118,8 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
118 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); 118 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
119 struct drm_device *drm_dev = dminor->dev; 119 struct drm_device *drm_dev = dminor->dev;
120 struct drm_i915_private *dev_priv = drm_dev->dev_private; 120 struct drm_i915_private *dev_priv = drm_dev->dev_private;
121 uint32_t misccpctl;
122 int slice = (int)(uintptr_t)attr->private; 121 int slice = (int)(uintptr_t)attr->private;
123 int i, ret; 122 int ret;
124 123
125 count = round_down(count, 4); 124 count = round_down(count, 4);
126 125
@@ -134,26 +133,13 @@ i915_l3_read(struct file *filp, struct kobject *kobj,
134 if (ret) 133 if (ret)
135 return ret; 134 return ret;
136 135
137 if (IS_HASWELL(drm_dev)) { 136 if (dev_priv->l3_parity.remap_info[slice])
138 if (dev_priv->l3_parity.remap_info[slice]) 137 memcpy(buf,
139 memcpy(buf, 138 dev_priv->l3_parity.remap_info[slice] + (offset/4),
140 dev_priv->l3_parity.remap_info[slice] + (offset/4), 139 count);
141 count); 140 else
142 else 141 memset(buf, 0, count);
143 memset(buf, 0, count);
144
145 goto out;
146 }
147
148 misccpctl = I915_READ(GEN7_MISCCPCTL);
149 I915_WRITE(GEN7_MISCCPCTL, misccpctl & ~GEN7_DOP_CLOCK_GATE_ENABLE);
150
151 for (i = 0; i < count; i += 4)
152 *((uint32_t *)(&buf[i])) = I915_READ(GEN7_L3LOG_BASE + offset + i);
153
154 I915_WRITE(GEN7_MISCCPCTL, misccpctl);
155 142
156out:
157 mutex_unlock(&drm_dev->struct_mutex); 143 mutex_unlock(&drm_dev->struct_mutex);
158 144
159 return count; 145 return count;
@@ -168,6 +154,7 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
168 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev); 154 struct drm_minor *dminor = container_of(dev, struct drm_minor, kdev);
169 struct drm_device *drm_dev = dminor->dev; 155 struct drm_device *drm_dev = dminor->dev;
170 struct drm_i915_private *dev_priv = drm_dev->dev_private; 156 struct drm_i915_private *dev_priv = drm_dev->dev_private;
157 struct i915_hw_context *ctx;
171 u32 *temp = NULL; /* Just here to make handling failures easy */ 158 u32 *temp = NULL; /* Just here to make handling failures easy */
172 int slice = (int)(uintptr_t)attr->private; 159 int slice = (int)(uintptr_t)attr->private;
173 int ret; 160 int ret;
@@ -176,6 +163,9 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
176 if (ret) 163 if (ret)
177 return ret; 164 return ret;
178 165
166 if (dev_priv->hw_contexts_disabled)
167 return -ENXIO;
168
179 ret = i915_mutex_lock_interruptible(drm_dev); 169 ret = i915_mutex_lock_interruptible(drm_dev);
180 if (ret) 170 if (ret)
181 return ret; 171 return ret;
@@ -204,8 +194,9 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
204 194
205 memcpy(dev_priv->l3_parity.remap_info[slice] + (offset/4), buf, count); 195 memcpy(dev_priv->l3_parity.remap_info[slice] + (offset/4), buf, count);
206 196
207 if (i915_gem_l3_remap(&dev_priv->ring[RCS], slice)) 197 /* NB: We defer the remapping until we switch to the context */
208 count = 0; 198 list_for_each_entry(ctx, &dev_priv->context_list, link)
199 ctx->remap_slice |= (1<<slice);
209 200
210 mutex_unlock(&drm_dev->struct_mutex); 201 mutex_unlock(&drm_dev->struct_mutex);
211 202