@@ -2245,6 +2245,7 @@ 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);
int i915_gem_context_open(struct drm_device *dev, struct drm_file *file);
+int i915_gem_context_enable(struct drm_i915_private *dev_priv);
void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
int i915_switch_context(struct intel_ring_buffer *ring,
struct drm_file *file, int to_id);
@@ -4489,14 +4489,16 @@ i915_gem_init_hw(struct drm_device *dev)
i915_gem_l3_remap(&dev_priv->ring[RCS], i);
/*
- * XXX: There was some w/a described somewhere suggesting loading
- * contexts before PPGTT.
+ * XXX: Contexts should only be initialized once. Doing a switch to the
+ * default context switch however is something we'd like to do after
+ * reset or thaw (the latter may not actually be necessary for HW, but
+ * goes with our code better). Context switching requires rings (for
+ * the do_switch), but before enabling PPGTT. So don't move this.
*/
- ret = i915_gem_context_init(dev);
+ ret = i915_gem_context_enable(dev_priv);
if (ret) {
- i915_gem_cleanup_ringbuffer(dev);
- DRM_ERROR("Context initialization failed %d\n", ret);
- return ret;
+ DRM_ERROR("Context enable failed %d\n", ret);
+ goto err_out;
}
if (dev_priv->mm.aliasing_ppgtt) {
@@ -4504,10 +4506,15 @@ i915_gem_init_hw(struct drm_device *dev)
if (ret) {
i915_gem_cleanup_aliasing_ppgtt(dev);
DRM_INFO("PPGTT enable failed. This is not fatal, but unexpected\n");
+ ret = 0;
}
}
return 0;
+
+err_out:
+ i915_gem_cleanup_ringbuffer(dev);
+ return ret;
}
int i915_gem_init(struct drm_device *dev)
@@ -4526,9 +4533,14 @@ int i915_gem_init(struct drm_device *dev)
i915_gem_init_global_gtt(dev);
+ ret = i915_gem_context_init(dev);
+ if (ret)
+ return ret;
+
ret = i915_gem_init_hw(dev);
mutex_unlock(&dev->struct_mutex);
if (ret) {
+ i915_gem_context_fini(dev);
i915_gem_cleanup_aliasing_ppgtt(dev);
drm_mm_takedown(&dev_priv->gtt.base.mm);
return ret;
@@ -237,19 +237,11 @@ static int create_default_context(struct drm_device *dev)
goto err_destroy;
}
- ret = do_switch(&dev_priv->ring[RCS], ctx);
- if (ret) {
- DRM_DEBUG_DRIVER("Switch failed %d\n", ret);
- goto err_unpin;
- }
-
dev_priv->ring[RCS].default_context = ctx;
DRM_DEBUG_DRIVER("Default HW context loaded\n");
return 0;
-err_unpin:
- i915_gem_object_ggtt_unpin(ctx->obj);
err_destroy:
i915_gem_context_unreference(ctx);
return ret;
@@ -307,8 +299,9 @@ int i915_gem_context_init(struct drm_device *dev)
if (!HAS_HW_CONTEXTS(dev))
return 0;
- /* If called from reset, or thaw... we've been here already */
- if (dev_priv->ring[RCS].default_context)
+ /* Init should only be called once per module load. Eventually the
+ * restriction on the context_disabled check can be loosened. */
+ if (WARN_ON(dev_priv->ring[RCS].default_context))
return 0;
dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
@@ -384,6 +377,28 @@ void i915_gem_context_fini(struct drm_device *dev)
i915_gem_context_unreference(dctx);
}
+int i915_gem_context_enable(struct drm_i915_private *dev_priv)
+{
+ struct intel_ring_buffer *ring;
+ int ret, i;
+
+ if (!HAS_HW_CONTEXTS(dev_priv->dev))
+ return 0;
+
+ /* FIXME: We should make this work, even in reset */
+ if (i915_reset_in_progress(&dev_priv->gpu_error))
+ return 0;
+
+ BUG_ON(!dev_priv->ring[RCS].default_context);
+ for_each_ring(ring, dev_priv, i) {
+ ret = do_switch(ring, ring->default_context);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
static int context_idr_cleanup(int id, void *p, void *data)
{
struct i915_hw_context *ctx = p;