Merge branches 'acpi-smbus', 'acpi-ec' and 'acpi-pci'
[deliverable/linux.git] / drivers / gpu / drm / i915 / intel_guc_loader.c
index 6ff7feab3c26ce0431e24d9bd54110885309b591..3541f76c65a7ab8ce1559bd34d14acb04ea47858 100644 (file)
@@ -59,7 +59,7 @@
  *
  */
 
-#define I915_SKL_GUC_UCODE "i915/skl_guc_ver3.bin"
+#define I915_SKL_GUC_UCODE "i915/skl_guc_ver4.bin"
 MODULE_FIRMWARE(I915_SKL_GUC_UCODE);
 
 /* User-friendly representation of an enum */
@@ -79,6 +79,43 @@ const char *intel_guc_fw_status_repr(enum intel_guc_fw_status status)
        }
 };
 
+static void direct_interrupts_to_host(struct drm_i915_private *dev_priv)
+{
+       struct intel_engine_cs *ring;
+       int i, irqs;
+
+       /* tell all command streamers NOT to forward interrupts and vblank to GuC */
+       irqs = _MASKED_FIELD(GFX_FORWARD_VBLANK_MASK, GFX_FORWARD_VBLANK_NEVER);
+       irqs |= _MASKED_BIT_DISABLE(GFX_INTERRUPT_STEERING);
+       for_each_ring(ring, dev_priv, i)
+               I915_WRITE(RING_MODE_GEN7(ring), irqs);
+
+       /* route all GT interrupts to the host */
+       I915_WRITE(GUC_BCS_RCS_IER, 0);
+       I915_WRITE(GUC_VCS2_VCS1_IER, 0);
+       I915_WRITE(GUC_WD_VECS_IER, 0);
+}
+
+static void direct_interrupts_to_guc(struct drm_i915_private *dev_priv)
+{
+       struct intel_engine_cs *ring;
+       int i, irqs;
+
+       /* 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);
+       for_each_ring(ring, dev_priv, i)
+               I915_WRITE(RING_MODE_GEN7(ring), irqs);
+
+       /* route USER_INTERRUPT to Host, all others are sent to GuC. */
+       irqs = GT_RENDER_USER_INTERRUPT << GEN8_RCS_IRQ_SHIFT |
+              GT_RENDER_USER_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
+       /* These three registers have the same bit definitions */
+       I915_WRITE(GUC_BCS_RCS_IER, ~irqs);
+       I915_WRITE(GUC_VCS2_VCS1_IER, ~irqs);
+       I915_WRITE(GUC_WD_VECS_IER, ~irqs);
+}
+
 static u32 get_gttype(struct drm_i915_private *dev_priv)
 {
        /* XXX: GT type based on PCI device ID? field seems unused by fw */
@@ -162,9 +199,10 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
                                      u32 *status)
 {
        u32 val = I915_READ(GUC_STATUS);
+       u32 uk_val = val & GS_UKERNEL_MASK;
        *status = val;
-       return ((val & GS_UKERNEL_MASK) == GS_UKERNEL_READY ||
-               (val & GS_UKERNEL_MASK) == GS_UKERNEL_LAPIC_DONE);
+       return (uk_val == GS_UKERNEL_READY ||
+               ((val & GS_MIA_CORE_STATE) && uk_val == GS_UKERNEL_LAPIC_DONE));
 }
 
 /*
@@ -179,10 +217,6 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
  * +-------------------------------+  ----
  * |         RSA signature         |  256B
  * +-------------------------------+  ----
- * |         RSA public Key        |  256B
- * +-------------------------------+  ----
- * |       Public key modulus      |    4B
- * +-------------------------------+  ----
  *
  * Architecturally, the DMA engine is bidirectional, and can potentially even
  * transfer between GTT locations. This functionality is left out of the API
@@ -197,7 +231,6 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
 #define UOS_VER_MAJOR_OFFSET           0x46
 #define UOS_CSS_HEADER_SIZE            0x80
 #define UOS_RSA_SIG_SIZE               0x100
-#define UOS_CSS_SIGNING_SIZE           0x204
 
 static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
 {
@@ -209,13 +242,13 @@ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
        int i, ret = 0;
 
        /* uCode size, also is where RSA signature starts */
-       offset = ucode_size = guc_fw->guc_fw_size - UOS_CSS_SIGNING_SIZE;
+       offset = ucode_size = guc_fw->guc_fw_size - UOS_RSA_SIG_SIZE;
        I915_WRITE(DMA_COPY_SIZE, ucode_size);
 
        /* Copy RSA signature from the fw image to HW for verification */
        sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, UOS_RSA_SIG_SIZE, offset);
        for (i = 0; i < UOS_RSA_SIG_SIZE / sizeof(u32); i++)
-               I915_WRITE(UOS_RSA_SCRATCH_0 + i * sizeof(u32), rsa[i]);
+               I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
 
        /* Set the source address for the new blob */
        offset = i915_gem_obj_ggtt_offset(fw_obj);
@@ -288,6 +321,13 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
        /* Enable MIA caching. GuC clock gating is disabled. */
        I915_WRITE(GUC_SHIM_CONTROL, GUC_SHIM_CONTROL_VALUE);
 
+       /* WaDisableMinuteIaClockGating:skl,bxt */
+       if ((IS_SKYLAKE(dev) && INTEL_REVID(dev) <= SKL_REVID_B0) ||
+           (IS_BROXTON(dev) && INTEL_REVID(dev) == BXT_REVID_A0)) {
+               I915_WRITE(GUC_SHIM_CONTROL, (I915_READ(GUC_SHIM_CONTROL) &
+                                             ~GUC_ENABLE_MIA_CLOCK_GATING));
+       }
+
        /* WaC6DisallowByGfxPause*/
        I915_WRITE(GEN6_GFXPAUSE, 0x30FFF);
 
@@ -342,6 +382,8 @@ int intel_guc_ucode_load(struct drm_device *dev)
                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;
 
@@ -389,12 +431,25 @@ int intel_guc_ucode_load(struct drm_device *dev)
                intel_guc_fw_status_repr(guc_fw->guc_fw_fetch_status),
                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);
+               if (err)
+                       goto fail;
+               direct_interrupts_to_guc(dev_priv);
+       }
+
        return 0;
 
 fail:
        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);
+
        return err;
 }
 
@@ -403,8 +458,8 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
        struct drm_i915_gem_object *obj;
        const struct firmware *fw;
        const u8 *css_header;
-       const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_CSS_SIGNING_SIZE;
-       const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_CSS_SIGNING_SIZE
+       const size_t minsize = UOS_CSS_HEADER_SIZE + UOS_RSA_SIG_SIZE;
+       const size_t maxsize = GUC_WOPCM_SIZE_VALUE + UOS_RSA_SIG_SIZE
                        - 0x8000; /* 32k reserved (8K stack + 24k context) */
        int err;
 
@@ -449,7 +504,9 @@ static void guc_fw_fetch(struct drm_device *dev, struct intel_guc_fw *guc_fw)
                        guc_fw->guc_fw_major_found, guc_fw->guc_fw_minor_found,
                        guc_fw->guc_fw_major_wanted, guc_fw->guc_fw_minor_wanted);
 
+       mutex_lock(&dev->struct_mutex);
        obj = i915_gem_object_create_from_data(dev, fw->data, fw->size);
+       mutex_unlock(&dev->struct_mutex);
        if (IS_ERR_OR_NULL(obj)) {
                err = obj ? PTR_ERR(obj) : -ENOMEM;
                goto fail;
@@ -485,8 +542,6 @@ fail:
  * @dev:       drm device
  *
  * Called early during driver load, but after GEM is initialised.
- * The device struct_mutex must be held by the caller, as we're
- * going to allocate a GEM object to hold the firmware image.
  *
  * The firmware will be transferred to the GuC's memory later,
  * when intel_guc_ucode_load() is called.
@@ -504,8 +559,8 @@ void intel_guc_ucode_init(struct drm_device *dev)
                fw_path = NULL;
        } else if (IS_SKYLAKE(dev)) {
                fw_path = I915_SKL_GUC_UCODE;
-               guc_fw->guc_fw_major_wanted = 3;
-               guc_fw->guc_fw_minor_wanted = 0;
+               guc_fw->guc_fw_major_wanted = 4;
+               guc_fw->guc_fw_minor_wanted = 3;
        } else {
                i915.enable_guc_submission = false;
                fw_path = "";   /* unknown device */
@@ -540,11 +595,14 @@ void intel_guc_ucode_fini(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
 
+       direct_interrupts_to_host(dev_priv);
        i915_guc_submission_fini(dev);
 
+       mutex_lock(&dev->struct_mutex);
        if (guc_fw->guc_fw_obj)
                drm_gem_object_unreference(&guc_fw->guc_fw_obj->base);
        guc_fw->guc_fw_obj = NULL;
+       mutex_unlock(&dev->struct_mutex);
 
        guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
 }
This page took 0.028446 seconds and 5 git commands to generate.