[Intel-gfx] [PATCH] drm/i915/guc: Fix a fw content lost issue after it is evicted

yu.dai at intel.com yu.dai at intel.com
Fri Nov 6 13:55:27 PST 2015


From: Alex Dai <yu.dai at intel.com>

We keep a copy of GuC fw in a GEM obj. However its content is lost
if the GEM obj is evicted (igt/gem_evict_*). Therefore, the later
fw loading during GPU reset will fail.

Now we keep the copy in a memory block rather than a GEM objet.
During fw loading, we will wrap up a GEM obj with fw data for DMA
copy. The GEM obj will be freed DMA is done.

Signed-off-by: Alex Dai <yu.dai at intel.com>
---
 drivers/gpu/drm/i915/intel_guc.h        |  2 +-
 drivers/gpu/drm/i915/intel_guc_loader.c | 84 +++++++++++++++------------------
 2 files changed, 39 insertions(+), 47 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_guc.h b/drivers/gpu/drm/i915/intel_guc.h
index 5ba5866..2714106 100644
--- a/drivers/gpu/drm/i915/intel_guc.h
+++ b/drivers/gpu/drm/i915/intel_guc.h
@@ -68,7 +68,7 @@ struct intel_guc_fw {
 	struct drm_device *		guc_dev;
 	const char *			guc_fw_path;
 	size_t				guc_fw_size;
-	struct drm_i915_gem_object *	guc_fw_obj;
+	uint32_t			*guc_fw_data;
 	enum intel_guc_fw_status	guc_fw_fetch_status;
 	enum intel_guc_fw_status	guc_fw_load_status;
 
diff --git a/drivers/gpu/drm/i915/intel_guc_loader.c b/drivers/gpu/drm/i915/intel_guc_loader.c
index 550921f..ebf15e8 100644
--- a/drivers/gpu/drm/i915/intel_guc_loader.c
+++ b/drivers/gpu/drm/i915/intel_guc_loader.c
@@ -218,26 +218,45 @@ static inline bool guc_ucode_response(struct drm_i915_private *dev_priv,
 static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
 {
 	struct intel_guc_fw *guc_fw = &dev_priv->guc.guc_fw;
-	struct drm_i915_gem_object *fw_obj = guc_fw->guc_fw_obj;
+	struct drm_i915_gem_object *fw_obj;
 	unsigned long offset;
-	struct sg_table *sg = fw_obj->pages;
-	u32 status, rsa[UOS_RSA_SCRATCH_MAX_COUNT];
+	u32 status, *rsa;
 	int i, ret = 0;
 
 	/* where RSA signature starts */
-	offset = guc_fw->rsa_offset;
+	rsa = (u32 *)((u8 *)guc_fw->guc_fw_data + guc_fw->rsa_offset);
 
 	/* Copy RSA signature from the fw image to HW for verification */
-	sg_pcopy_to_buffer(sg->sgl, sg->nents, rsa, sizeof(rsa), offset);
 	for (i = 0; i < UOS_RSA_SCRATCH_MAX_COUNT; i++)
-		I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
+		I915_WRITE(UOS_RSA_SCRATCH(i), *(rsa + i));
+
+	/* Wrap up a gem obj filled with header + ucode */
+	fw_obj = i915_gem_object_create_from_data(dev_priv->dev,
+			(u8 *)guc_fw->guc_fw_data + guc_fw->header_offset,
+			guc_fw->header_size + guc_fw->ucode_size);
+	if (IS_ERR_OR_NULL(fw_obj)) {
+		ret = fw_obj ? PTR_ERR(fw_obj) : -ENOMEM;
+		return ret;
+	}
+
+	ret = i915_gem_object_set_to_gtt_domain(fw_obj, false);
+	if (ret) {
+		DRM_DEBUG_DRIVER("set-domain failed %d\n", ret);
+		return ret;
+	}
+
+	ret = i915_gem_obj_ggtt_pin(fw_obj, 0, 0);
+	if (ret) {
+		DRM_DEBUG_DRIVER("pin failed %d\n", ret);
+		return ret;
+	}
 
 	/* The header plus uCode will be copied to WOPCM via DMA, excluding any
 	 * other components */
 	I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size);
 
 	/* Set the source address for the new blob */
-	offset = i915_gem_obj_ggtt_offset(fw_obj) + guc_fw->header_offset;
+	offset = i915_gem_obj_ggtt_offset(fw_obj);
 	I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
 	I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
 
@@ -269,6 +288,10 @@ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
 		ret = -ENOEXEC;
 	}
 
+	/* We can free it now that DMA has completed */
+	i915_gem_object_ggtt_unpin(fw_obj);
+	drm_gem_object_unreference(&fw_obj->base);
+
 	DRM_DEBUG_DRIVER("returning %d\n", ret);
 
 	return ret;
@@ -279,22 +302,9 @@ static int guc_ucode_xfer_dma(struct drm_i915_private *dev_priv)
  */
 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;
 	int ret;
 
-	ret = i915_gem_object_set_to_gtt_domain(guc_fw->guc_fw_obj, false);
-	if (ret) {
-		DRM_DEBUG_DRIVER("set-domain failed %d\n", ret);
-		return ret;
-	}
-
-	ret = i915_gem_obj_ggtt_pin(guc_fw->guc_fw_obj, 0, 0);
-	if (ret) {
-		DRM_DEBUG_DRIVER("pin failed %d\n", ret);
-		return ret;
-	}
-
 	/* Invalidate GuC TLB to let GuC take the latest updates to GTT. */
 	I915_WRITE(GEN8_GTCR, GEN8_GTCR_INVALIDATE);
 
@@ -337,12 +347,6 @@ static int guc_ucode_xfer(struct drm_i915_private *dev_priv)
 
 	intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
 
-	/*
-	 * We keep the object pages for reuse during resume. But we can unpin it
-	 * now that DMA has completed, so it doesn't continue to take up space.
-	 */
-	i915_gem_object_ggtt_unpin(guc_fw->guc_fw_obj);
-
 	return ret;
 }
 
@@ -444,7 +448,6 @@ fail:
 
 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;
 	struct guc_css_header *css;
 	size_t size;
@@ -530,34 +533,27 @@ 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;
+	guc_fw->guc_fw_data = kmalloc(fw->size, GFP_KERNEL);
+	if (guc_fw->guc_fw_data == NULL) {
+		err = -ENOMEM;
 		goto fail;
 	}
 
-	guc_fw->guc_fw_obj = obj;
+	memcpy(guc_fw->guc_fw_data, fw->data, fw->size);
 	guc_fw->guc_fw_size = fw->size;
 
-	DRM_DEBUG_DRIVER("GuC fw fetch status SUCCESS, obj %p\n",
-			guc_fw->guc_fw_obj);
+	DRM_DEBUG_DRIVER("GuC fw fetch status SUCCESS\n");
 
 	release_firmware(fw);
 	guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_SUCCESS;
 	return;
 
 fail:
-	DRM_DEBUG_DRIVER("GuC fw fetch status FAIL; err %d, fw %p, obj %p\n",
-		err, fw, guc_fw->guc_fw_obj);
+	DRM_DEBUG_DRIVER("GuC fw fetch status FAIL; err %d, fw %p\n", err, fw);
 	DRM_ERROR("Failed to fetch GuC firmware from %s (error %d)\n",
 		  guc_fw->guc_fw_path, err);
 
-	obj = guc_fw->guc_fw_obj;
-	if (obj)
-		drm_gem_object_unreference(&obj->base);
-	guc_fw->guc_fw_obj = NULL;
+	guc_fw->guc_fw_data = NULL;
 
 	release_firmware(fw);		/* OK even if fw is NULL */
 	guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_FAIL;
@@ -627,11 +623,7 @@ void intel_guc_ucode_fini(struct drm_device *dev)
 	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);
+	kfree(guc_fw->guc_fw_data);
 
 	guc_fw->guc_fw_fetch_status = GUC_FIRMWARE_NONE;
 }
-- 
2.5.0



More information about the Intel-gfx mailing list