Merge tag 'powerpc-4.8-2' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[cascardo/linux.git] / drivers / gpu / drm / i915 / intel_guc_loader.c
index 876e5da..605c696 100644 (file)
  *
  */
 
-#define I915_SKL_GUC_UCODE "i915/skl_guc_ver6.bin"
+#define I915_SKL_GUC_UCODE "i915/skl_guc_ver6_1.bin"
 MODULE_FIRMWARE(I915_SKL_GUC_UCODE);
 
+#define I915_BXT_GUC_UCODE "i915/bxt_guc_ver8_7.bin"
+MODULE_FIRMWARE(I915_BXT_GUC_UCODE);
+
+#define I915_KBL_GUC_UCODE "i915/kbl_guc_ver9_14.bin"
+MODULE_FIRMWARE(I915_KBL_GUC_UCODE);
+
 /* User-friendly representation of an enum */
 const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status)
 {
@@ -84,7 +90,7 @@ static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
        struct intel_engine_cs *engine;
        int irqs;
 
-       /* tell all command streamers NOT to forward interrupts and vblank to GuC */
+       /* tell all command streamers NOT to forward interrupts or vblank to GuC */
        irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_NEVER);
        irqs |= _MASKED_BIT_DISABLE(GFX_INTERRUPT_STEERING);
        for_each_engine(engine, dev_priv)
@@ -100,10 +106,10 @@ static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
 {
        struct intel_engine_cs *engine;
        int irqs;
+       u32 tmp;
 
-       /* tell all command streamers to forward interrupts and vblank to GuC */
-       irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_ALWAYS);
-       irqs |= _MASKED_BIT_ENABLE(GFX_INTERRUPT_STEERING);
+       /* tell all command streamers to forward interrupts (but not vblank) to GuC */
+       irqs = _MASKED_BIT_ENABLE(GFX_INTERRUPT_STEERING);
        for_each_engine(engine, dev_priv)
                I915_WRITE(RING_MODE_GEN7(engine), irqs);
 
@@ -114,6 +120,16 @@ static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
        I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
        I915_WRITE(GUC_VCS2_VCS1_IER, ~irqs);
        I915_WRITE(GUC_WD_VECS_IER, ~irqs);
+
+       /*
+        * If GuC has routed PM interrupts to itself, don't keep it.
+        * and keep other interrupts those are unmasked by GuC.
+       */
+       tmp = I915_READ(GEN6_PMINTRMSK);
+       if (tmp & GEN8_PMINTR_REDIRECT_TO_NON_DISP) {
+               dev_priv->rps.pm_intr_keep |= ~(tmp & ~GEN8_PMINTR_REDIRECT_TO_NON_DISP);
+               dev_priv->rps.pm_intr_keep &= ~GEN8_PMINTR_REDIRECT_TO_NON_DISP;
+       }
 }
 
 static u32 get_gttype(struct drm_i915_private *dev_priv)
@@ -281,13 +297,24 @@ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
        return ret;
 }
 
+static u32 guc_wopcm_size(struct drm_i915_private *dev_priv)
+{
+       u32 wopcm_size = GUC_WOPCM_TOP;
+
+       /* On BXT, the top of WOPCM is reserved for RC6 context */
+       if (IS_BROXTON(dev_priv))
+               wopcm_size -= BXT_GUC_WOPCM_RC6_RESERVED;
+
+       return wopcm_size;
+}
+
 /*
  * Load the GuC firmware blob into the MinuteIA.
  */
 static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
 {
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
-       struct drm_device *dev = dev_priv->dev;
+       struct drm_device *dev = &dev_priv->drm;
        int ret;
 
        ret = i915_gem_object_set_to_gtt_domain(guc_fw->guc_fw_obj, false);
@@ -308,7 +335,7 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
        intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
 
        /* init WOPCM */
-       I915_WRITE(GUC_WOPCM_SIZE, GUC_WOPCM_SIZE_VALUE);
+       I915_WRITE(GUC_WOPCM_SIZE, guc_wopcm_size(dev_priv));
        I915_WRITE(DMA_GUC_WOPCM_OFFSET, GUC_WOPCM_OFFSET_VALUE);
 
        /* Enable MIA caching. GuC clock gating is disabled. */
@@ -372,66 +399,63 @@ static int i915_reset_guc(struct drm_i915_private *dev_priv)
 }
 
 /**
- * intel_guc_ucode_load() - load GuC uCode into the device
+ * intel_guc_setup() - finish preparing the GuC for activity
  * @dev:       drm device
  *
  * Called from gem_init_hw() during driver loading and also after a GPU reset.
  *
+ * The main action required here it to load the GuC uCode into the device.
  * The firmware image should have already been fetched into memory by the
- * earlier call to intel_guc_ucode_init(), so here we need only check that
- * is succeeded, and then transfer the image to the h/w.
+ * earlier call to intel_guc_init(), so here we need only check that worked,
+ * and then transfer the image to the h/w.
  *
  * Return:     non-zero code on error
  */
-int intel_guc_ucode_load(struct drm_device *dev)
+int intel_guc_setup(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
-       int retries, err = 0;
+       const char *fw_path = guc_fw->guc_fw_path;
+       int retries, ret, err;
 
-       if (!i915.enable_guc_submission)
-               return 0;
-
-       DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
+       DRM_DEBUG_DRIVER("GuC fw status: path %s, fetch %s, load %s\n",
+               fw_path,
                intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
                intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
 
-       direct_interrupts_to_host(dev_priv);
-
-       if (guc_fw->guc_fw_fetch_status == GUC_FIRMWARE_NONE)
-               return 0;
-
-       if (guc_fw->guc_fw_fetch_status == GUC_FIRMWARE_SUCCESS &&
-           guc_fw->guc_fw_load_status == GUC_FIRMWARE_FAIL)
-               return -ENOEXEC;
-
-       guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
-
-       DRM_DEBUG_DRIVER("GuC fw fetch status %s\n",
-               intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status));
-
-       switch (guc_fw->guc_fw_fetch_status) {
-       case GUC_FIRMWARE_FAIL:
-               /* something went wrong :( */
-               err = -EIO;
+       /* Loading forbidden, or no firmware to load? */
+       if (!i915.enable_guc_loading) {
+               err = 0;
                goto fail;
-
-       case GUC_FIRMWARE_NONE:
-       case GUC_FIRMWARE_PENDING:
-       default:
-               /* "can't happen" */
-               WARN_ONCE(1, "GuC fw %s invalid guc_fw_fetch_status %s [%d]\n",
-                       guc_fw->guc_fw_path,
-                       intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
-                       guc_fw->guc_fw_fetch_status);
+       } else if (fw_path == NULL) {
+               /* Device is known to have no uCode (e.g. no GuC) */
                err = -ENXIO;
                goto fail;
+       } else if (*fw_path == '\0') {
+               /* Device has a GuC but we don't know what f/w to load? */
+               DRM_INFO("No GuC firmware known for this platform\n");
+               err = -ENODEV;
+               goto fail;
+       }
 
-       case GUC_FIRMWARE_SUCCESS:
-               break;
+       /* Fetch failed, or already fetched but failed to load? */
+       if (guc_fw->guc_fw_fetch_status != GUC_FIRMWARE_SUCCESS) {
+               err = -EIO;
+               goto fail;
+       } else if (guc_fw->guc_fw_load_status == GUC_FIRMWARE_FAIL) {
+               err = -ENOEXEC;
+               goto fail;
        }
 
-       err = i915_guc_submission_init(dev);
+       direct_interrupts_to_host(dev_priv);
+
+       guc_fw->guc_fw_load_status = GUC_FIRMWARE_PENDING;
+
+       DRM_DEBUG_DRIVER("GuC fw status: fetch %s, load %s\n",
+               intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
+               intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
+
+       err = i915_guc_submission_init(dev_priv);
        if (err)
                goto fail;
 
@@ -448,7 +472,7 @@ int intel_guc_ucode_load(struct drm_device *dev)
                 */
                err = i915_reset_guc(dev_priv);
                if (err) {
-                       DRM_ERROR("GuC reset failed, err %d\n", err);
+                       DRM_ERROR("GuC reset failed: %d\n", err);
                        goto fail;
                }
 
@@ -459,8 +483,8 @@ int intel_guc_ucode_load(struct drm_device *dev)
                if (--retries == 0)
                        goto fail;
 
-               DRM_INFO("GuC fw load failed, err %d; will reset and "
-                       "retry %d more time(s)\n", err, retries);
+               DRM_INFO("GuC fw load failed: %d; will reset and "
+                        "retry %d more time(s)\n", err, retries);
        }
 
        guc_fw->guc_fw_load_status = GUC_FIRMWARE_SUCCESS;
@@ -470,10 +494,7 @@ int intel_guc_ucode_load(struct drm_device *dev)
                intel_guc_fw_status_repr(guc_fw->guc_fw_load_status));
 
        if (i915.enable_guc_submission) {
-               /* The execbuf_client will be recreated. Release it first. */
-               i915_guc_submission_disable(dev);
-
-               err = i915_guc_submission_enable(dev);
+               err = i915_guc_submission_enable(dev_priv);
                if (err)
                        goto fail;
                direct_interrupts_to_guc(dev_priv);
@@ -482,15 +503,50 @@ int intel_guc_ucode_load(struct drm_device *dev)
        return 0;
 
 fail:
-       DRM_ERROR("GuC firmware load failed, err %d\n", err);
        if (guc_fw->guc_fw_load_status == GUC_FIRMWARE_PENDING)
                guc_fw->guc_fw_load_status = GUC_FIRMWARE_FAIL;
 
        direct_interrupts_to_host(dev_priv);
-       i915_guc_submission_disable(dev);
-       i915_guc_submission_fini(dev);
+       i915_guc_submission_disable(dev_priv);
+       i915_guc_submission_fini(dev_priv);
 
-       return err;
+       /*
+        * We've failed to load the firmware :(
+        *
+        * Decide whether to disable GuC submission and fall back to
+        * execlist mode, and whether to hide the error by returning
+        * zero or to return -EIO, which the caller will treat as a
+        * nonfatal error (i.e. it doesn't prevent driver load, but
+        * marks the GPU as wedged until reset).
+        */
+       if (i915.enable_guc_loading > 1) {
+               ret = -EIO;
+       } else if (i915.enable_guc_submission > 1) {
+               ret = -EIO;
+       } else {
+               ret = 0;
+       }
+
+       if (err == 0 && !HAS_GUC_UCODE(dev))
+               ;       /* Don't mention the GuC! */
+       else if (err == 0)
+               DRM_INFO("GuC firmware load skipped\n");
+       else if (ret != -EIO)
+               DRM_INFO("GuC firmware load failed: %d\n", err);
+       else
+               DRM_ERROR("GuC firmware load failed: %d\n", err);
+
+       if (i915.enable_guc_submission) {
+               if (fw_path == NULL)
+                       DRM_INFO("GuC submission without firmware not supported\n");
+               if (ret == 0)
+                       DRM_INFO("Falling back from GuC submission to execlist mode\n");
+               else
+                       DRM_ERROR("GuC init failed: %d\n", ret);
+       }
+       i915.enable_guc_submission = 0;
+
+       return ret;
 }
 
 static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
@@ -552,9 +608,7 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
 
        /* Header and uCode will be loaded to WOPCM. Size of the two. */
        size = guc_fw->header_size + guc_fw->ucode_size;
-
-       /* Top 32k of WOPCM is reserved (8K stack + 24k RC6 context). */
-       if (size > GUC_WOPCM_SIZE_VALUE - 0x8000) {
+       if (size > guc_wopcm_size(to_i915(dev))) {
                DRM_ERROR("Firmware is too large to fit in WOPCM\n");
                goto fail;
        }
@@ -617,22 +671,25 @@ fail:
 }
 
 /**
- * intel_guc_ucode_init() - define parameters and fetch firmware
+ * intel_guc_init() - define parameters and fetch firmware
  * @dev:       drm device
  *
  * Called early during driver load, but after GEM is initialised.
  *
  * The firmware will be transferred to the GuC's memory later,
- * when intel_guc_ucode_load() is called.
+ * when intel_guc_setup() is called.
  */
-void intel_guc_ucode_init(struct drm_device *dev)
+void intel_guc_init(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
        const char *fw_path;
 
-       if (!HAS_GUC_SCHED(dev))
-               i915.enable_guc_submission = false;
+       /* A negative value means "use platform default" */
+       if (i915.enable_guc_loading < 0)
+               i915.enable_guc_loading = HAS_GUC_UCODE(dev);
+       if (i915.enable_guc_submission < 0)
+               i915.enable_guc_submission = HAS_GUC_SCHED(dev);
 
        if (!HAS_GUC_UCODE(dev)) {
                fw_path = NULL;
@@ -640,27 +697,30 @@ void intel_guc_ucode_init(struct drm_device *dev)
                fw_path = I915_SKL_GUC_UCODE;
                guc_fw->guc_fw_major_wanted = 6;
                guc_fw->guc_fw_minor_wanted = 1;
+       } else if (IS_BROXTON(dev)) {
+               fw_path = I915_BXT_GUC_UCODE;
+               guc_fw->guc_fw_major_wanted = 8;
+               guc_fw->guc_fw_minor_wanted = 7;
+       } else if (IS_KABYLAKE(dev)) {
+               fw_path = I915_KBL_GUC_UCODE;
+               guc_fw->guc_fw_major_wanted = 9;
+               guc_fw->guc_fw_minor_wanted = 14;
        } else {
-               i915.enable_guc_submission = false;
                fw_path = "";   /* unknown device */
        }
 
-       if (!i915.enable_guc_submission)
-               return;
-
        guc_fw->guc_dev = dev;
        guc_fw->guc_fw_path = fw_path;
        guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
        guc_fw->guc_fw_load_status = GUC_FIRMWARE_NONE;
 
+       /* Early (and silent) return if GuC loading is disabled */
+       if (!i915.enable_guc_loading)
+               return;
        if (fw_path == NULL)
                return;
-
-       if (*fw_path == '\0') {
-               DRM_ERROR("No GuC firmware known for this platform\n");
-               guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_FAIL;
+       if (*fw_path == '\0')
                return;
-       }
 
        guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_PENDING;
        DRM_DEBUG_DRIVER("GuC firmware pending, path %s\n", fw_path);
@@ -669,18 +729,18 @@ void intel_guc_ucode_init(struct drm_device *dev)
 }
 
 /**
- * intel_guc_ucode_fini() - clean up all allocated resources
+ * intel_guc_fini() - clean up all allocated resources
  * @dev:       drm device
  */
-void intel_guc_ucode_fini(struct drm_device *dev)
+void intel_guc_fini(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_private *dev_priv = to_i915(dev);
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
 
        mutex_lock(&dev->struct_mutex);
        direct_interrupts_to_host(dev_priv);
-       i915_guc_submission_disable(dev);
-       i915_guc_submission_fini(dev);
+       i915_guc_submission_disable(dev_priv);
+       i915_guc_submission_fini(dev_priv);
 
        if (guc_fw->guc_fw_obj)
                drm_gem_object_unreference(&guc_fw->guc_fw_obj->base);