drm/i915: fix guest virtual PCH detection on non-PCH systems
[linux-2.6-microblaze.git] / drivers / gpu / drm / i915 / i915_drv.c
index 84ca369..8f22ae8 100644 (file)
@@ -67,6 +67,7 @@ bool __i915_inject_load_failure(const char *func, int line)
        if (++i915_load_fail_count == i915_modparams.inject_load_failure) {
                DRM_INFO("Injecting failure at checkpoint %u [%s:%d]\n",
                         i915_modparams.inject_load_failure, func, line);
+               i915_modparams.inject_load_failure = 0;
                return true;
        }
 
@@ -101,7 +102,13 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level,
                   __builtin_return_address(0), &vaf);
 
        if (is_error && !shown_bug_once) {
-               dev_notice(kdev, "%s", FDO_BUG_MSG);
+               /*
+                * Ask the user to file a bug report for the error, except
+                * if they may have caused the bug by fiddling with unsafe
+                * module parameters.
+                */
+               if (!test_taint(TAINT_USER))
+                       dev_notice(kdev, "%s", FDO_BUG_MSG);
                shown_bug_once = true;
        }
 
@@ -111,16 +118,15 @@ __i915_printk(struct drm_i915_private *dev_priv, const char *level,
 static bool i915_error_injected(struct drm_i915_private *dev_priv)
 {
 #if IS_ENABLED(CONFIG_DRM_I915_DEBUG)
-       return i915_modparams.inject_load_failure &&
-              i915_load_fail_count == i915_modparams.inject_load_failure;
+       return i915_load_fail_count && !i915_modparams.inject_load_failure;
 #else
        return false;
 #endif
 }
 
-#define i915_load_error(dev_priv, fmt, ...)                                 \
-       __i915_printk(dev_priv,                                              \
-                     i915_error_injected(dev_priv) ? KERN_DEBUG : KERN_ERR, \
+#define i915_load_error(i915, fmt, ...)                                         \
+       __i915_printk(i915,                                              \
+                     i915_error_injected(i915) ? KERN_DEBUG : KERN_ERR, \
                      fmt, ##__VA_ARGS__)
 
 /* Map PCH device id to PCH type, or PCH_NONE if unknown. */
@@ -227,6 +233,8 @@ intel_virt_detect_pch(const struct drm_i915_private *dev_priv)
                id = INTEL_PCH_SPT_DEVICE_ID_TYPE;
        else if (IS_COFFEELAKE(dev_priv) || IS_CANNONLAKE(dev_priv))
                id = INTEL_PCH_CNP_DEVICE_ID_TYPE;
+       else if (IS_ICELAKE(dev_priv))
+               id = INTEL_PCH_ICP_DEVICE_ID_TYPE;
 
        if (id)
                DRM_DEBUG_KMS("Assuming PCH ID %04x\n", id);
@@ -281,7 +289,7 @@ static void intel_detect_pch(struct drm_i915_private *dev_priv)
                                if (WARN_ON(pch_type == PCH_NONE))
                                        pch_type = PCH_NOP;
                        } else {
-                               pch_type = PCH_NOP;
+                               pch_type = PCH_NONE;
                        }
                        dev_priv->pch_type = pch_type;
                        dev_priv->pch_id = id;
@@ -377,9 +385,9 @@ static int i915_getparam_ioctl(struct drm_device *dev, void *data,
                value = INTEL_INFO(dev_priv)->sseu.min_eu_in_pool;
                break;
        case I915_PARAM_HUC_STATUS:
-               intel_runtime_pm_get(dev_priv);
-               value = I915_READ(HUC_STATUS2) & HUC_FW_VERIFIED;
-               intel_runtime_pm_put(dev_priv);
+               value = intel_huc_check_status(&dev_priv->huc);
+               if (value < 0)
+                       return value;
                break;
        case I915_PARAM_MMAP_GTT_VERSION:
                /* Though we've started our numbering from 1, and so class all
@@ -628,26 +636,6 @@ static const struct vga_switcheroo_client_ops i915_switcheroo_ops = {
        .can_switch = i915_switcheroo_can_switch,
 };
 
-static void i915_gem_fini(struct drm_i915_private *dev_priv)
-{
-       /* Flush any outstanding unpin_work. */
-       i915_gem_drain_workqueue(dev_priv);
-
-       mutex_lock(&dev_priv->drm.struct_mutex);
-       intel_uc_fini_hw(dev_priv);
-       intel_uc_fini(dev_priv);
-       i915_gem_cleanup_engines(dev_priv);
-       i915_gem_contexts_fini(dev_priv);
-       mutex_unlock(&dev_priv->drm.struct_mutex);
-
-       intel_uc_fini_misc(dev_priv);
-       i915_gem_cleanup_userptr(dev_priv);
-
-       i915_gem_drain_freed_objects(dev_priv);
-
-       WARN_ON(!list_empty(&dev_priv->contexts.list));
-}
-
 static int i915_load_modeset_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
@@ -695,11 +683,9 @@ static int i915_load_modeset_init(struct drm_device *dev)
        if (ret)
                goto cleanup_irq;
 
-       intel_uc_init_fw(dev_priv);
-
        ret = i915_gem_init(dev_priv);
        if (ret)
-               goto cleanup_uc;
+               goto cleanup_irq;
 
        intel_setup_overlay(dev_priv);
 
@@ -719,8 +705,6 @@ cleanup_gem:
        if (i915_gem_suspend(dev_priv))
                DRM_ERROR("failed to idle hardware; continuing to unload!\n");
        i915_gem_fini(dev_priv);
-cleanup_uc:
-       intel_uc_fini_fw(dev_priv);
 cleanup_irq:
        drm_irq_uninstall(dev);
        intel_teardown_gmbus(dev_priv);
@@ -922,16 +906,21 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
        mutex_init(&dev_priv->wm.wm_mutex);
        mutex_init(&dev_priv->pps_mutex);
 
-       intel_uc_init_early(dev_priv);
        i915_memcpy_init_early(dev_priv);
 
        ret = i915_workqueues_init(dev_priv);
        if (ret < 0)
                goto err_engines;
 
+       ret = i915_gem_init_early(dev_priv);
+       if (ret < 0)
+               goto err_workqueues;
+
        /* This must be called before any calls to HAS_PCH_* */
        intel_detect_pch(dev_priv);
 
+       intel_wopcm_init_early(&dev_priv->wopcm);
+       intel_uc_init_early(dev_priv);
        intel_pm_setup(dev_priv);
        intel_init_dpio(dev_priv);
        intel_power_domains_init(dev_priv);
@@ -940,18 +929,13 @@ static int i915_driver_init_early(struct drm_i915_private *dev_priv,
        intel_init_display_hooks(dev_priv);
        intel_init_clock_gating_hooks(dev_priv);
        intel_init_audio_hooks(dev_priv);
-       ret = i915_gem_load_init(dev_priv);
-       if (ret < 0)
-               goto err_irq;
-
        intel_display_crc_init(dev_priv);
 
        intel_detect_preproduction_hw(dev_priv);
 
        return 0;
 
-err_irq:
-       intel_irq_fini(dev_priv);
+err_workqueues:
        i915_workqueues_cleanup(dev_priv);
 err_engines:
        i915_engines_cleanup(dev_priv);
@@ -964,8 +948,9 @@ err_engines:
  */
 static void i915_driver_cleanup_early(struct drm_i915_private *dev_priv)
 {
-       i915_gem_load_cleanup(dev_priv);
        intel_irq_fini(dev_priv);
+       intel_uc_cleanup_early(dev_priv);
+       i915_gem_cleanup_early(dev_priv);
        i915_workqueues_cleanup(dev_priv);
        i915_engines_cleanup(dev_priv);
 }
@@ -1035,6 +1020,10 @@ static int i915_driver_init_mmio(struct drm_i915_private *dev_priv)
 
        intel_uncore_init(dev_priv);
 
+       intel_device_info_init_mmio(dev_priv);
+
+       intel_uncore_prune(dev_priv);
+
        intel_uc_init_mmio(dev_priv);
 
        ret = intel_engines_init_mmio(dev_priv);
@@ -1077,8 +1066,6 @@ static void intel_sanitize_options(struct drm_i915_private *dev_priv)
                                            i915_modparams.enable_ppgtt);
        DRM_DEBUG_DRIVER("ppgtt mode: %i\n", i915_modparams.enable_ppgtt);
 
-       intel_uc_sanitize_options(dev_priv);
-
        intel_gvt_sanitize_options(dev_priv);
 }
 
@@ -1105,30 +1092,32 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
 
        ret = i915_ggtt_probe_hw(dev_priv);
        if (ret)
-               return ret;
+               goto err_perf;
 
-       /* WARNING: Apparently we must kick fbdev drivers before vgacon,
-        * otherwise the vga fbdev driver falls over. */
+       /*
+        * WARNING: Apparently we must kick fbdev drivers before vgacon,
+        * otherwise the vga fbdev driver falls over.
+        */
        ret = i915_kick_out_firmware_fb(dev_priv);
        if (ret) {
                DRM_ERROR("failed to remove conflicting framebuffer drivers\n");
-               goto out_ggtt;
+               goto err_ggtt;
        }
 
        ret = i915_kick_out_vgacon(dev_priv);
        if (ret) {
                DRM_ERROR("failed to remove conflicting VGA console\n");
-               goto out_ggtt;
+               goto err_ggtt;
        }
 
        ret = i915_ggtt_init_hw(dev_priv);
        if (ret)
-               return ret;
+               goto err_ggtt;
 
        ret = i915_ggtt_enable_hw(dev_priv);
        if (ret) {
                DRM_ERROR("failed to enable GGTT\n");
-               goto out_ggtt;
+               goto err_ggtt;
        }
 
        pci_set_master(pdev);
@@ -1139,7 +1128,7 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
                if (ret) {
                        DRM_ERROR("failed to set DMA mask\n");
 
-                       goto out_ggtt;
+                       goto err_ggtt;
                }
        }
 
@@ -1157,7 +1146,7 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
                if (ret) {
                        DRM_ERROR("failed to set DMA mask\n");
 
-                       goto out_ggtt;
+                       goto err_ggtt;
                }
        }
 
@@ -1190,13 +1179,14 @@ static int i915_driver_init_hw(struct drm_i915_private *dev_priv)
 
        ret = intel_gvt_init(dev_priv);
        if (ret)
-               goto out_ggtt;
+               goto err_ggtt;
 
        return 0;
 
-out_ggtt:
+err_ggtt:
        i915_ggtt_cleanup_hw(dev_priv);
-
+err_perf:
+       i915_perf_fini(dev_priv);
        return ret;
 }
 
@@ -1241,7 +1231,6 @@ static void i915_driver_register(struct drm_i915_private *dev_priv)
        /* Reveal our presence to userspace */
        if (drm_dev_register(dev, 0) == 0) {
                i915_debugfs_register(dev_priv);
-               i915_guc_log_register(dev_priv);
                i915_setup_sysfs(dev_priv);
 
                /* Depends on sysfs having been initialized */
@@ -1301,7 +1290,6 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv)
        i915_pmu_unregister(dev_priv);
 
        i915_teardown_sysfs(dev_priv);
-       i915_guc_log_unregister(dev_priv);
        drm_dev_unregister(&dev_priv->drm);
 
        i915_gem_shrinker_unregister(dev_priv);
@@ -1460,7 +1448,6 @@ void i915_driver_unload(struct drm_device *dev)
        i915_reset_error_state(dev_priv);
 
        i915_gem_fini(dev_priv);
-       intel_uc_fini_fw(dev_priv);
        intel_fbc_cleanup_cfb(dev_priv);
 
        intel_power_domains_fini(dev_priv);
@@ -1548,12 +1535,30 @@ static bool suspend_to_idle(struct drm_i915_private *dev_priv)
        return false;
 }
 
+static int i915_drm_prepare(struct drm_device *dev)
+{
+       struct drm_i915_private *i915 = to_i915(dev);
+       int err;
+
+       /*
+        * NB intel_display_suspend() may issue new requests after we've
+        * ostensibly marked the GPU as ready-to-sleep here. We need to
+        * split out that work and pull it forward so that after point,
+        * the GPU is not woken again.
+        */
+       err = i915_gem_suspend(i915);
+       if (err)
+               dev_err(&i915->drm.pdev->dev,
+                       "GEM idle failed, suspend/resume might fail\n");
+
+       return err;
+}
+
 static int i915_drm_suspend(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = to_i915(dev);
        struct pci_dev *pdev = dev_priv->drm.pdev;
        pci_power_t opregion_target_state;
-       int error;
 
        /* ignore lid events during suspend */
        mutex_lock(&dev_priv->modeset_restore_lock);
@@ -1570,13 +1575,6 @@ static int i915_drm_suspend(struct drm_device *dev)
 
        pci_save_state(pdev);
 
-       error = i915_gem_suspend(dev_priv);
-       if (error) {
-               dev_err(&pdev->dev,
-                       "GEM idle failed, resume might fail\n");
-               goto out;
-       }
-
        intel_display_suspend(dev);
 
        intel_dp_mst_suspend(dev);
@@ -1595,7 +1593,6 @@ static int i915_drm_suspend(struct drm_device *dev)
        opregion_target_state = suspend_to_idle(dev_priv) ? PCI_D1 : PCI_D3cold;
        intel_opregion_notify_adapter(dev_priv, opregion_target_state);
 
-       intel_uncore_suspend(dev_priv);
        intel_opregion_unregister(dev_priv);
 
        intel_fbdev_set_suspend(dev, FBINFO_STATE_SUSPENDED, true);
@@ -1604,10 +1601,9 @@ static int i915_drm_suspend(struct drm_device *dev)
 
        intel_csr_ucode_suspend(dev_priv);
 
-out:
        enable_rpm_wakeref_asserts(dev_priv);
 
-       return error;
+       return 0;
 }
 
 static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
@@ -1618,7 +1614,10 @@ static int i915_drm_suspend_late(struct drm_device *dev, bool hibernation)
 
        disable_rpm_wakeref_asserts(dev_priv);
 
+       i915_gem_suspend_late(dev_priv);
+
        intel_display_set_init_power(dev_priv, false);
+       intel_uncore_suspend(dev_priv);
 
        /*
         * In case of firmware assisted context save/restore don't manually
@@ -1873,7 +1872,8 @@ static int i915_resume_switcheroo(struct drm_device *dev)
 /**
  * i915_reset - reset chip after a hang
  * @i915: #drm_i915_private to reset
- * @flags: Instructions
+ * @stalled_mask: mask of the stalled engines with the guilty requests
+ * @reason: user error message for why we are resetting
  *
  * Reset the chip.  Useful if a hang is detected. Marks the device as wedged
  * on failure.
@@ -1888,12 +1888,16 @@ static int i915_resume_switcheroo(struct drm_device *dev)
  *   - re-init interrupt state
  *   - re-init display
  */
-void i915_reset(struct drm_i915_private *i915, unsigned int flags)
+void i915_reset(struct drm_i915_private *i915,
+               unsigned int stalled_mask,
+               const char *reason)
 {
        struct i915_gpu_error *error = &i915->gpu_error;
        int ret;
        int i;
 
+       GEM_TRACE("flags=%lx\n", error->flags);
+
        might_sleep();
        lockdep_assert_held(&i915->drm.struct_mutex);
        GEM_BUG_ON(!test_bit(I915_RESET_BACKOFF, &error->flags));
@@ -1905,8 +1909,8 @@ void i915_reset(struct drm_i915_private *i915, unsigned int flags)
        if (!i915_gem_unset_wedged(i915))
                goto wakeup;
 
-       if (!(flags & I915_RESET_QUIET))
-               dev_notice(i915->drm.dev, "Resetting chip after gpu hang\n");
+       if (reason)
+               dev_notice(i915->drm.dev, "Resetting chip for %s\n", reason);
        error->reset_count++;
 
        disable_irq(i915->drm.irq);
@@ -1949,7 +1953,7 @@ void i915_reset(struct drm_i915_private *i915, unsigned int flags)
                goto error;
        }
 
-       i915_gem_reset(i915);
+       i915_gem_reset(i915, stalled_mask);
        intel_overlay_reset(i915);
 
        /*
@@ -1995,7 +1999,6 @@ taint:
 error:
        i915_gem_set_wedged(i915);
        i915_retire_requests(i915);
-       intel_gpu_reset(i915, ALL_ENGINES);
        goto finish;
 }
 
@@ -2008,7 +2011,7 @@ static inline int intel_gt_reset_engine(struct drm_i915_private *dev_priv,
 /**
  * i915_reset_engine - reset GPU engine to recover from a hang
  * @engine: engine to reset
- * @flags: options
+ * @msg: reason for GPU reset; or NULL for no dev_notice()
  *
  * Reset a specific GPU engine. Useful if a hang is detected.
  * Returns zero on successful reset or otherwise an error code.
@@ -2018,12 +2021,13 @@ static inline int intel_gt_reset_engine(struct drm_i915_private *dev_priv,
  *  - reset engine (which will force the engine to idle)
  *  - re-init/configure engine
  */
-int i915_reset_engine(struct intel_engine_cs *engine, unsigned int flags)
+int i915_reset_engine(struct intel_engine_cs *engine, const char *msg)
 {
        struct i915_gpu_error *error = &engine->i915->gpu_error;
        struct i915_request *active_request;
        int ret;
 
+       GEM_TRACE("%s flags=%lx\n", engine->name, error->flags);
        GEM_BUG_ON(!test_bit(I915_RESET_ENGINE + engine->id, &error->flags));
 
        active_request = i915_gem_reset_prepare_engine(engine);
@@ -2033,10 +2037,9 @@ int i915_reset_engine(struct intel_engine_cs *engine, unsigned int flags)
                goto out;
        }
 
-       if (!(flags & I915_RESET_QUIET)) {
+       if (msg)
                dev_notice(engine->i915->drm.dev,
-                          "Resetting %s after gpu hang\n", engine->name);
-       }
+                          "Resetting %s for %s\n", engine->name, msg);
        error->reset_engine_count[engine->id]++;
 
        if (!engine->i915->guc.execbuf_client)
@@ -2056,7 +2059,7 @@ int i915_reset_engine(struct intel_engine_cs *engine, unsigned int flags)
         * active request and can drop it, adjust head to skip the offending
         * request to resume executing remaining requests in the queue.
         */
-       i915_gem_reset_engine(engine, active_request);
+       i915_gem_reset_engine(engine, active_request, true);
 
        /*
         * The engine and its registers (and workarounds in case of render)
@@ -2072,6 +2075,22 @@ out:
        return ret;
 }
 
+static int i915_pm_prepare(struct device *kdev)
+{
+       struct pci_dev *pdev = to_pci_dev(kdev);
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       if (!dev) {
+               dev_err(kdev, "DRM not initialized, aborting suspend.\n");
+               return -ENODEV;
+       }
+
+       if (dev->switch_power_state == DRM_SWITCH_POWER_OFF)
+               return 0;
+
+       return i915_drm_prepare(dev);
+}
+
 static int i915_pm_suspend(struct device *kdev)
 {
        struct pci_dev *pdev = to_pci_dev(kdev);
@@ -2465,10 +2484,13 @@ static void vlv_wait_for_gt_wells(struct drm_i915_private *dev_priv,
        /*
         * RC6 transitioning can be delayed up to 2 msec (see
         * valleyview_enable_rps), use 3 msec for safety.
+        *
+        * This can fail to turn off the rc6 if the GPU is stuck after a failed
+        * reset and we are trying to force the machine to sleep.
         */
        if (vlv_wait_for_pw_status(dev_priv, mask, val))
-               DRM_ERROR("timeout waiting for GT wells to go %s\n",
-                         onoff(wait_for_on));
+               DRM_DEBUG_DRIVER("timeout waiting for GT wells to go %s\n",
+                                onoff(wait_for_on));
 }
 
 static void vlv_check_no_gt_access(struct drm_i915_private *dev_priv)
@@ -2719,6 +2741,7 @@ const struct dev_pm_ops i915_pm_ops = {
         * S0ix (via system suspend) and S3 event handlers [PMSG_SUSPEND,
         * PMSG_RESUME]
         */
+       .prepare = i915_pm_prepare,
        .suspend = i915_pm_suspend,
        .suspend_late = i915_pm_suspend_late,
        .resume_early = i915_pm_resume_early,