drm/i915: Pass intel_gt to has-reset?
[linux-2.6-block.git] / drivers / gpu / drm / i915 / gt / intel_reset.c
index ec85740de942f582602e31f18b411db6e6463fff..ea5cf3a28fbe20a085f49e383f1930df8759807a 100644 (file)
@@ -42,11 +42,10 @@ static void engine_skip_context(struct i915_request *rq)
        struct intel_engine_cs *engine = rq->engine;
        struct i915_gem_context *hung_ctx = rq->gem_context;
 
-       lockdep_assert_held(&engine->active.lock);
-
        if (!i915_request_is_active(rq))
                return;
 
+       lockdep_assert_held(&engine->active.lock);
        list_for_each_entry_continue(rq, &engine->active.requests, sched.link)
                if (rq->gem_context == hung_ctx)
                        i915_request_skip(rq, -EIO);
@@ -123,7 +122,6 @@ void __i915_request_reset(struct i915_request *rq, bool guilty)
                  rq->fence.seqno,
                  yesno(guilty));
 
-       lockdep_assert_held(&rq->engine->active.lock);
        GEM_BUG_ON(i915_request_completed(rq));
 
        if (guilty) {
@@ -309,7 +307,7 @@ static int gen6_reset_engines(struct intel_gt *gt,
        return gen6_hw_domain_reset(gt, hw_mask);
 }
 
-static u32 gen11_lock_sfc(struct intel_engine_cs *engine)
+static int gen11_lock_sfc(struct intel_engine_cs *engine, u32 *hw_mask)
 {
        struct intel_uncore *uncore = engine->uncore;
        u8 vdbox_sfc_access = RUNTIME_INFO(engine->i915)->vdbox_sfc_access;
@@ -318,6 +316,7 @@ static u32 gen11_lock_sfc(struct intel_engine_cs *engine)
        i915_reg_t sfc_usage;
        u32 sfc_usage_bit;
        u32 sfc_reset_bit;
+       int ret;
 
        switch (engine->class) {
        case VIDEO_DECODE_CLASS:
@@ -352,27 +351,33 @@ static u32 gen11_lock_sfc(struct intel_engine_cs *engine)
        }
 
        /*
-        * Tell the engine that a software reset is going to happen. The engine
-        * will then try to force lock the SFC (if currently locked, it will
-        * remain so until we tell the engine it is safe to unlock; if currently
-        * unlocked, it will ignore this and all new lock requests). If SFC
-        * ends up being locked to the engine we want to reset, we have to reset
-        * it as well (we will unlock it once the reset sequence is completed).
+        * If the engine is using a SFC, tell the engine that a software reset
+        * is going to happen. The engine will then try to force lock the SFC.
+        * If SFC ends up being locked to the engine we want to reset, we have
+        * to reset it as well (we will unlock it once the reset sequence is
+        * completed).
         */
+       if (!(intel_uncore_read_fw(uncore, sfc_usage) & sfc_usage_bit))
+               return 0;
+
        rmw_set_fw(uncore, sfc_forced_lock, sfc_forced_lock_bit);
 
-       if (__intel_wait_for_register_fw(uncore,
-                                        sfc_forced_lock_ack,
-                                        sfc_forced_lock_ack_bit,
-                                        sfc_forced_lock_ack_bit,
-                                        1000, 0, NULL)) {
-               DRM_DEBUG_DRIVER("Wait for SFC forced lock ack failed\n");
+       ret = __intel_wait_for_register_fw(uncore,
+                                          sfc_forced_lock_ack,
+                                          sfc_forced_lock_ack_bit,
+                                          sfc_forced_lock_ack_bit,
+                                          1000, 0, NULL);
+
+       /* Was the SFC released while we were trying to lock it? */
+       if (!(intel_uncore_read_fw(uncore, sfc_usage) & sfc_usage_bit))
                return 0;
-       }
 
-       if (intel_uncore_read_fw(uncore, sfc_usage) & sfc_usage_bit)
-               return sfc_reset_bit;
+       if (ret) {
+               DRM_DEBUG_DRIVER("Wait for SFC forced lock ack failed\n");
+               return ret;
+       }
 
+       *hw_mask |= sfc_reset_bit;
        return 0;
 }
 
@@ -430,12 +435,21 @@ static int gen11_reset_engines(struct intel_gt *gt,
                for_each_engine_masked(engine, gt->i915, engine_mask, tmp) {
                        GEM_BUG_ON(engine->id >= ARRAY_SIZE(hw_engine_mask));
                        hw_mask |= hw_engine_mask[engine->id];
-                       hw_mask |= gen11_lock_sfc(engine);
+                       ret = gen11_lock_sfc(engine, &hw_mask);
+                       if (ret)
+                               goto sfc_unlock;
                }
        }
 
        ret = gen6_hw_domain_reset(gt, hw_mask);
 
+sfc_unlock:
+       /*
+        * We unlock the SFC based on the lock status and not the result of
+        * gen11_lock_sfc to make sure that we clean properly if something
+        * wrong happened during the lock (e.g. lock acquired after timeout
+        * expiration).
+        */
        if (engine_mask != ALL_ENGINES)
                for_each_engine_masked(engine, gt->i915, engine_mask, tmp)
                        gen11_unlock_sfc(engine);
@@ -532,8 +546,10 @@ typedef int (*reset_func)(struct intel_gt *,
                          intel_engine_mask_t engine_mask,
                          unsigned int retry);
 
-static reset_func intel_get_gpu_reset(struct drm_i915_private *i915)
+static reset_func intel_get_gpu_reset(const struct intel_gt *gt)
 {
+       struct drm_i915_private *i915 = gt->i915;
+
        if (INTEL_GEN(i915) >= 8)
                return gen8_reset_engines;
        else if (INTEL_GEN(i915) >= 6)
@@ -557,7 +573,7 @@ int __intel_gt_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask)
        int ret = -ETIMEDOUT;
        int retry;
 
-       reset = intel_get_gpu_reset(gt->i915);
+       reset = intel_get_gpu_reset(gt);
        if (!reset)
                return -ENODEV;
 
@@ -577,17 +593,20 @@ int __intel_gt_reset(struct intel_gt *gt, intel_engine_mask_t engine_mask)
        return ret;
 }
 
-bool intel_has_gpu_reset(struct drm_i915_private *i915)
+bool intel_has_gpu_reset(const struct intel_gt *gt)
 {
        if (!i915_modparams.reset)
                return NULL;
 
-       return intel_get_gpu_reset(i915);
+       return intel_get_gpu_reset(gt);
 }
 
-bool intel_has_reset_engine(struct drm_i915_private *i915)
+bool intel_has_reset_engine(const struct intel_gt *gt)
 {
-       return INTEL_INFO(i915)->has_reset_engine && i915_modparams.reset >= 2;
+       if (i915_modparams.reset < 2)
+               return false;
+
+       return INTEL_INFO(gt->i915)->has_reset_engine;
 }
 
 int intel_reset_guc(struct intel_gt *gt)
@@ -697,7 +716,7 @@ static void reset_finish_engine(struct intel_engine_cs *engine)
        engine->reset.finish(engine);
        intel_uncore_forcewake_put(engine->uncore, FORCEWAKE_ALL);
 
-       intel_engine_signal_breadcrumbs(engine);
+       intel_engine_breadcrumbs_irq(engine);
 }
 
 static void reset_finish(struct intel_gt *gt, intel_engine_mask_t awake)
@@ -792,11 +811,13 @@ static bool __intel_gt_unset_wedged(struct intel_gt *gt)
 {
        struct intel_gt_timelines *timelines = &gt->timelines;
        struct intel_timeline *tl;
+       unsigned long flags;
 
        if (!test_bit(I915_WEDGED, &gt->reset.flags))
                return true;
 
-       if (!gt->scratch) /* Never full initialised, recovery impossible */
+       /* Never fully initialised, recovery impossible */
+       if (test_bit(I915_WEDGED_ON_INIT, &gt->reset.flags))
                return false;
 
        GEM_TRACE("start\n");
@@ -811,7 +832,7 @@ static bool __intel_gt_unset_wedged(struct intel_gt *gt)
         *
         * No more can be submitted until we reset the wedged bit.
         */
-       mutex_lock(&timelines->mutex);
+       spin_lock_irqsave(&timelines->lock, flags);
        list_for_each_entry(tl, &timelines->active_list, link) {
                struct i915_request *rq;
 
@@ -819,6 +840,8 @@ static bool __intel_gt_unset_wedged(struct intel_gt *gt)
                if (!rq)
                        continue;
 
+               spin_unlock_irqrestore(&timelines->lock, flags);
+
                /*
                 * All internal dependencies (i915_requests) will have
                 * been flushed by the set-wedge, but we may be stuck waiting
@@ -828,8 +851,12 @@ static bool __intel_gt_unset_wedged(struct intel_gt *gt)
                 */
                dma_fence_default_wait(&rq->fence, false, MAX_SCHEDULE_TIMEOUT);
                i915_request_put(rq);
+
+               /* Restart iteration after droping lock */
+               spin_lock_irqsave(&timelines->lock, flags);
+               tl = list_entry(&timelines->active_list, typeof(*tl), link);
        }
-       mutex_unlock(&timelines->mutex);
+       spin_unlock_irqrestore(&timelines->lock, flags);
 
        intel_gt_sanitize(gt, false);
 
@@ -936,7 +963,7 @@ void intel_gt_reset(struct intel_gt *gt,
 
        awake = reset_prepare(gt);
 
-       if (!intel_has_gpu_reset(gt->i915)) {
+       if (!intel_has_gpu_reset(gt)) {
                if (i915_modparams.reset)
                        dev_err(gt->i915->drm.dev, "GPU reset not supported\n");
                else
@@ -965,7 +992,7 @@ void intel_gt_reset(struct intel_gt *gt,
         * was running at the time of the reset (i.e. we weren't VT
         * switched away).
         */
-       ret = i915_gem_init_hw(gt->i915);
+       ret = intel_gt_init_hw(gt);
        if (ret) {
                DRM_ERROR("Failed to initialise HW following reset (%d)\n",
                          ret);
@@ -1157,7 +1184,7 @@ void intel_gt_handle_error(struct intel_gt *gt,
         * Try engine reset when available. We fall back to full reset if
         * single reset fails.
         */
-       if (intel_has_reset_engine(gt->i915) && !intel_gt_is_wedged(gt)) {
+       if (intel_has_reset_engine(gt) && !intel_gt_is_wedged(gt)) {
                for_each_engine_masked(engine, gt->i915, engine_mask, tmp) {
                        BUILD_BUG_ON(I915_RESET_MODESET >= I915_RESET_ENGINE);
                        if (test_and_set_bit(I915_RESET_ENGINE + engine->id,
@@ -1207,10 +1234,8 @@ out:
        intel_runtime_pm_put(&gt->i915->runtime_pm, wakeref);
 }
 
-int intel_gt_reset_trylock(struct intel_gt *gt)
+int intel_gt_reset_trylock(struct intel_gt *gt, int *srcu)
 {
-       int srcu;
-
        might_lock(&gt->reset.backoff_srcu);
        might_sleep();
 
@@ -1225,10 +1250,10 @@ int intel_gt_reset_trylock(struct intel_gt *gt)
 
                rcu_read_lock();
        }
-       srcu = srcu_read_lock(&gt->reset.backoff_srcu);
+       *srcu = srcu_read_lock(&gt->reset.backoff_srcu);
        rcu_read_unlock();
 
-       return srcu;
+       return 0;
 }
 
 void intel_gt_reset_unlock(struct intel_gt *gt, int tag)
@@ -1260,6 +1285,14 @@ int intel_gt_terminally_wedged(struct intel_gt *gt)
        return intel_gt_is_wedged(gt) ? -EIO : 0;
 }
 
+void intel_gt_set_wedged_on_init(struct intel_gt *gt)
+{
+       BUILD_BUG_ON(I915_RESET_ENGINE + I915_NUM_ENGINES >
+                    I915_WEDGED_ON_INIT);
+       intel_gt_set_wedged(gt);
+       set_bit(I915_WEDGED_ON_INIT, &gt->reset.flags);
+}
+
 void intel_gt_init_reset(struct intel_gt *gt)
 {
        init_waitqueue_head(&gt->reset.queue);