[PATCH v3 24/25] drm/i915/uc: Place uC firmware in upper range of GGTT

Michal Wajdeczko michal.wajdeczko at intel.com
Tue Apr 16 15:43:24 UTC 2019


From: Fernando Pacheco <fernando.pacheco at intel.com>

Currently we pin the GuC or HuC firmware image just
before uploading. Perma-pin during uC initialization
instead and use the range reserved at the top of the
address space.

Moving the firmware resulted in needing to:
- restore the ggtt mapping during the suspend/resume path.
- use an additional pinning for the rsa signature which will
  be used during HuC auth as addresses above GUC_GGTT_TOP
  do not map through GTT.

v2: Remove call to set to gtt domain
    Do not restore fw gtt mapping unconditionally
    Only attempt fw gtt pin/unpin if fw fetch success
v3: rebased

Signed-off-by: Fernando Pacheco <fernando.pacheco at intel.com>
Signed-off-by: Michal Wajdeczko <michal.wajdeczko at intel.com>
---
 drivers/gpu/drm/i915/i915_gem.c     |   2 +
 drivers/gpu/drm/i915/intel_guc.c    |   9 ++-
 drivers/gpu/drm/i915/intel_guc_fw.c |  43 +++++++++---
 drivers/gpu/drm/i915/intel_guc_fw.h |   3 +
 drivers/gpu/drm/i915/intel_huc.c    |  71 +++++++++++++++-----
 drivers/gpu/drm/i915/intel_huc.h    |   5 ++
 drivers/gpu/drm/i915/intel_huc_fw.c |  80 ++++++++++++++++++----
 drivers/gpu/drm/i915/intel_huc_fw.h |   3 +
 drivers/gpu/drm/i915/intel_uc.c     |  49 ++++++++++++--
 drivers/gpu/drm/i915/intel_uc.h     |   1 +
 drivers/gpu/drm/i915/intel_uc_fw.c  | 100 +++++++++++++++++++---------
 drivers/gpu/drm/i915/intel_uc_fw.h  |  12 +++-
 12 files changed, 306 insertions(+), 72 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index ac64a6fd9b91..9b065f4f4888 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -4508,6 +4508,8 @@ void i915_gem_resume(struct drm_i915_private *i915)
 	i915_gem_restore_gtt_mappings(i915);
 	i915_gem_restore_fences(i915);
 
+	intel_uc_restore_ggtt_mapping(i915);
+
 	/*
 	 * As we didn't flush the kernel context before suspend, we cannot
 	 * guarantee that the context image is complete. So let's just reset
diff --git a/drivers/gpu/drm/i915/intel_guc.c b/drivers/gpu/drm/i915/intel_guc.c
index 5e5c2c931226..fd470895e31c 100644
--- a/drivers/gpu/drm/i915/intel_guc.c
+++ b/drivers/gpu/drm/i915/intel_guc.c
@@ -214,9 +214,13 @@ int intel_guc_init(struct intel_guc *guc)
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
 	int ret;
 
-	ret = guc_shared_data_create(guc);
+	ret = intel_guc_fw_ggtt_pin(guc);
 	if (ret)
 		goto err_fetch;
+
+	ret = guc_shared_data_create(guc);
+	if (ret)
+		goto err_fw_pin;
 	GEM_BUG_ON(!guc->shared_data);
 
 	ret = intel_guc_log_create(&guc->log);
@@ -245,6 +249,8 @@ int intel_guc_init(struct intel_guc *guc)
 	intel_guc_log_destroy(&guc->log);
 err_shared:
 	guc_shared_data_destroy(guc);
+err_fw_pin:
+	intel_guc_fw_ggtt_unpin(guc);
 err_fetch:
 	intel_uc_fw_fini(&guc->fw);
 	return ret;
@@ -262,6 +268,7 @@ void intel_guc_fini(struct intel_guc *guc)
 	intel_guc_ads_destroy(guc);
 	intel_guc_log_destroy(&guc->log);
 	guc_shared_data_destroy(guc);
+	intel_guc_fw_ggtt_unpin(guc);
 	intel_uc_fw_fini(&guc->fw);
 }
 
diff --git a/drivers/gpu/drm/i915/intel_guc_fw.c b/drivers/gpu/drm/i915/intel_guc_fw.c
index edda8930a293..f17bcd3e12ac 100644
--- a/drivers/gpu/drm/i915/intel_guc_fw.c
+++ b/drivers/gpu/drm/i915/intel_guc_fw.c
@@ -27,6 +27,8 @@
  *    Alex Dai <yu.dai at intel.com>
  */
 
+#include <linux/types.h>
+
 #include "intel_guc_fw.h"
 #include "i915_drv.h"
 
@@ -139,14 +141,16 @@ static void guc_prepare_xfer(struct intel_guc *guc)
 }
 
 /* Copy RSA signature from the fw image to HW for verification */
-static void guc_xfer_rsa(struct intel_guc *guc, struct i915_vma *vma)
+static void guc_xfer_rsa(struct intel_guc *guc)
 {
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
+	struct intel_uc_fw *fw = &guc->fw;
+	struct sg_table *pages = fw->obj->mm.pages;
 	u32 rsa[UOS_RSA_SCRATCH_COUNT];
 	int i;
 
-	sg_pcopy_to_buffer(vma->pages->sgl, vma->pages->nents,
-			   rsa, sizeof(rsa), guc->fw.rsa_offset);
+	sg_pcopy_to_buffer(pages->sgl, pages->nents,
+			   rsa, sizeof(rsa), fw->rsa_offset);
 
 	for (i = 0; i < UOS_RSA_SCRATCH_COUNT; i++)
 		I915_WRITE(UOS_RSA_SCRATCH(i), rsa[i]);
@@ -218,7 +222,7 @@ static int guc_wait_ucode(struct intel_guc *guc)
  * transfer between GTT locations. This functionality is left out of the API
  * for now as there is no need for it.
  */
-static int guc_xfer_ucode(struct intel_guc *guc, struct i915_vma *vma)
+static int guc_xfer_ucode(struct intel_guc *guc)
 {
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
 	struct intel_uc_fw *guc_fw = &guc->fw;
@@ -231,7 +235,7 @@ static int guc_xfer_ucode(struct intel_guc *guc, struct i915_vma *vma)
 	I915_WRITE(DMA_COPY_SIZE, guc_fw->header_size + guc_fw->ucode_size);
 
 	/* Set the source address for the new blob */
-	offset = intel_guc_ggtt_offset(guc, vma) + guc_fw->header_offset;
+	offset = intel_guc_fw_ggtt_offset(guc) + guc_fw->header_offset;
 	I915_WRITE(DMA_ADDR_0_LOW, lower_32_bits(offset));
 	I915_WRITE(DMA_ADDR_0_HIGH, upper_32_bits(offset) & 0xFFFF);
 
@@ -250,7 +254,7 @@ static int guc_xfer_ucode(struct intel_guc *guc, struct i915_vma *vma)
 /*
  * Load the GuC firmware blob into the MinuteIA.
  */
-static int guc_fw_xfer(struct intel_uc_fw *guc_fw, struct i915_vma *vma)
+static int guc_fw_xfer(struct intel_uc_fw *guc_fw)
 {
 	struct intel_guc *guc = container_of(guc_fw, struct intel_guc, fw);
 	struct drm_i915_private *dev_priv = guc_to_i915(guc);
@@ -267,9 +271,9 @@ static int guc_fw_xfer(struct intel_uc_fw *guc_fw, struct i915_vma *vma)
 	 * by the DMA engine in one operation, whereas the RSA signature is
 	 * loaded via MMIO.
 	 */
-	guc_xfer_rsa(guc, vma);
+	guc_xfer_rsa(guc);
 
-	ret = guc_xfer_ucode(guc, vma);
+	ret = guc_xfer_ucode(guc);
 
 	intel_uncore_forcewake_put(&dev_priv->uncore, FORCEWAKE_ALL);
 
@@ -292,3 +296,26 @@ int intel_guc_fw_upload(struct intel_guc *guc)
 {
 	return intel_uc_fw_upload(&guc->fw, guc_fw_xfer);
 }
+
+int intel_guc_fw_ggtt_pin(struct intel_guc *guc)
+{
+	struct drm_i915_private *i915 = guc_to_i915(guc);
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	u64 slot = intel_guc_fw_ggtt_offset(guc);
+
+	return intel_uc_fw_ggtt_pin(&guc->fw, ggtt, slot);
+}
+
+void intel_guc_fw_ggtt_unpin(struct intel_guc *guc)
+{
+	struct drm_i915_private *i915 = guc_to_i915(guc);
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	u64 slot = intel_guc_fw_ggtt_offset(guc);
+
+	intel_uc_fw_ggtt_unpin(&guc->fw, ggtt, slot);
+}
+
+u32 intel_guc_fw_ggtt_offset(struct intel_guc *guc)
+{
+	return intel_uc_fw_ggtt_offset(&guc->fw);
+}
diff --git a/drivers/gpu/drm/i915/intel_guc_fw.h b/drivers/gpu/drm/i915/intel_guc_fw.h
index 4ec5d3d9e2b0..a4610dec59bf 100644
--- a/drivers/gpu/drm/i915/intel_guc_fw.h
+++ b/drivers/gpu/drm/i915/intel_guc_fw.h
@@ -29,5 +29,8 @@ struct intel_guc;
 
 void intel_guc_fw_init_early(struct intel_guc *guc);
 int intel_guc_fw_upload(struct intel_guc *guc);
+int intel_guc_fw_ggtt_pin(struct intel_guc *guc);
+void intel_guc_fw_ggtt_unpin(struct intel_guc *guc);
+u32 intel_guc_fw_ggtt_offset(struct intel_guc *guc);
 
 #endif
diff --git a/drivers/gpu/drm/i915/intel_huc.c b/drivers/gpu/drm/i915/intel_huc.c
index 70042f108048..bfbe382807a9 100644
--- a/drivers/gpu/drm/i915/intel_huc.c
+++ b/drivers/gpu/drm/i915/intel_huc.c
@@ -52,6 +52,59 @@ int intel_huc_init_misc(struct intel_huc *huc)
 	return 0;
 }
 
+/*
+ * The HuC firmware image now sits above GUC_GGTT_TOP and this
+ * portion does not map through GTT. This means GuC cannot
+ * perform the HuC auth with the rsa signature sitting in that
+ * range. We resort to additionally perma-pinning the rsa signature
+ * below GUC_GGTT_TOP and utilizing this mapping to perform
+ * the authentication.
+ */
+static int intel_huc_rsa_data_create(struct intel_huc *huc)
+{
+	struct drm_i915_private *i915 = huc_to_i915(huc);
+	struct intel_guc *guc = &i915->guc;
+	struct i915_vma *vma;
+	void *vaddr;
+
+	vma = intel_guc_allocate_vma(guc, PAGE_SIZE);
+	if (IS_ERR(vma))
+		return PTR_ERR(vma);
+
+	vaddr = i915_gem_object_pin_map(vma->obj, I915_MAP_WB);
+	if (IS_ERR(vaddr)) {
+		i915_vma_unpin_and_release(&vma, 0);
+		return PTR_ERR(vaddr);
+	}
+
+	huc->rsa_data = vma;
+	huc->rsa_data_vaddr = vaddr;
+
+	return 0;
+}
+
+static void intel_huc_rsa_data_destroy(struct intel_huc *huc)
+{
+	i915_vma_unpin_and_release(&huc->rsa_data, I915_VMA_RELEASE_MAP);
+}
+
+int intel_huc_init(struct intel_huc *huc)
+{
+	int err;
+
+	err = intel_huc_rsa_data_create(huc);
+	if (err)
+		return err;
+
+	return intel_huc_fw_ggtt_pin(huc);
+}
+
+void intel_huc_fini(struct intel_huc *huc)
+{
+	intel_huc_fw_ggtt_unpin(huc);
+	intel_huc_rsa_data_destroy(huc);
+}
+
 /**
  * intel_huc_auth() - Authenticate HuC uCode
  * @huc: intel_huc structure
@@ -67,26 +120,17 @@ int intel_huc_auth(struct intel_huc *huc)
 {
 	struct drm_i915_private *i915 = huc_to_i915(huc);
 	struct intel_guc *guc = &i915->guc;
-	struct i915_vma *vma;
 	int ret;
 
 	if (huc->fw.load_status != INTEL_UC_FIRMWARE_SUCCESS)
 		return -ENOEXEC;
 
-	vma = i915_gem_object_ggtt_pin(huc->fw.obj, NULL, 0, 0,
-				       PIN_OFFSET_BIAS | i915->ggtt.pin_bias);
-	if (IS_ERR(vma)) {
-		ret = PTR_ERR(vma);
-		DRM_ERROR("HuC: Failed to pin huc fw object %d\n", ret);
-		goto fail;
-	}
 
 	ret = intel_guc_auth_huc(guc,
-				 intel_guc_ggtt_offset(guc, vma) +
-				 huc->fw.rsa_offset);
+				 intel_guc_ggtt_offset(guc, huc->rsa_data));
 	if (ret) {
 		DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret);
-		goto fail_unpin;
+		goto fail;
 	}
 
 	/* Check authentication status, it should be done by now */
@@ -97,14 +141,11 @@ int intel_huc_auth(struct intel_huc *huc)
 					2, 50, NULL);
 	if (ret) {
 		DRM_ERROR("HuC: Firmware not verified %d\n", ret);
-		goto fail_unpin;
+		goto fail;
 	}
 
-	i915_vma_unpin(vma);
 	return 0;
 
-fail_unpin:
-	i915_vma_unpin(vma);
 fail:
 	huc->fw.load_status = INTEL_UC_FIRMWARE_FAIL;
 
diff --git a/drivers/gpu/drm/i915/intel_huc.h b/drivers/gpu/drm/i915/intel_huc.h
index c539794e4bd4..93895af3eca0 100644
--- a/drivers/gpu/drm/i915/intel_huc.h
+++ b/drivers/gpu/drm/i915/intel_huc.h
@@ -39,10 +39,15 @@ struct intel_huc {
 		u32 mask;
 		u32 value;
 	} status;
+
+	struct i915_vma *rsa_data;
+	void *rsa_data_vaddr;
 };
 
 void intel_huc_init_early(struct intel_huc *huc);
 int intel_huc_init_misc(struct intel_huc *huc);
+int intel_huc_init(struct intel_huc *huc);
+void intel_huc_fini(struct intel_huc *huc);
 int intel_huc_auth(struct intel_huc *huc);
 int intel_huc_check_status(struct intel_huc *huc);
 
diff --git a/drivers/gpu/drm/i915/intel_huc_fw.c b/drivers/gpu/drm/i915/intel_huc_fw.c
index d156212d6433..20d8099bb576 100644
--- a/drivers/gpu/drm/i915/intel_huc_fw.c
+++ b/drivers/gpu/drm/i915/intel_huc_fw.c
@@ -4,6 +4,8 @@
  * Copyright © 2014-2018 Intel Corporation
  */
 
+#include <linux/types.h>
+
 #include "intel_huc_fw.h"
 #include "i915_drv.h"
 
@@ -105,18 +107,20 @@ void intel_huc_fw_init_early(struct intel_huc *huc)
 	huc_fw_select(huc_fw);
 }
 
-/**
- * huc_fw_xfer() - DMA's the firmware
- * @huc_fw: the firmware descriptor
- * @vma: the firmware image (bound into the GGTT)
- *
- * Transfer the firmware image to RAM for execution by the microcontroller.
- *
- * Return: 0 on success, non-zero on failure
- */
-static int huc_fw_xfer(struct intel_uc_fw *huc_fw, struct i915_vma *vma)
+/* Copy RSA signature from the fw image to within GuC addressable range */
+static void huc_xfer_rsa(struct intel_huc *huc)
 {
-	struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw);
+	struct intel_uc_fw *fw = &huc->fw;
+	struct sg_table *pages = fw->obj->mm.pages;
+
+	sg_pcopy_to_buffer(pages->sgl, pages->nents,
+			   huc->rsa_data_vaddr, fw->rsa_size,
+			   fw->rsa_offset);
+}
+
+static int huc_xfer_ucode(struct intel_huc *huc)
+{
+	struct intel_uc_fw *huc_fw = &huc->fw;
 	struct drm_i915_private *dev_priv = huc_to_i915(huc);
 	struct intel_uncore *uncore = &dev_priv->uncore;
 	unsigned long offset = 0;
@@ -128,7 +132,7 @@ static int huc_fw_xfer(struct intel_uc_fw *huc_fw, struct i915_vma *vma)
 	intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
 
 	/* Set the source address for the uCode */
-	offset = intel_guc_ggtt_offset(&dev_priv->guc, vma) +
+	offset = intel_huc_fw_ggtt_offset(huc) +
 		 huc_fw->header_offset;
 	intel_uncore_write(uncore, DMA_ADDR_0_LOW,
 			   lower_32_bits(offset));
@@ -162,6 +166,23 @@ static int huc_fw_xfer(struct intel_uc_fw *huc_fw, struct i915_vma *vma)
 	return ret;
 }
 
+/**
+ * huc_fw_xfer() - DMA's the firmware
+ * @huc_fw: the firmware descriptor
+ *
+ * Transfer the firmware image to RAM for execution by the microcontroller.
+ *
+ * Return: 0 on success, non-zero on failure
+ */
+static int huc_fw_xfer(struct intel_uc_fw *huc_fw)
+{
+	struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw);
+
+	huc_xfer_rsa(huc);
+
+	return huc_xfer_ucode(huc);
+}
+
 /**
  * intel_huc_fw_upload() - load HuC uCode to device
  * @huc: intel_huc structure
@@ -178,3 +199,38 @@ int intel_huc_fw_upload(struct intel_huc *huc)
 {
 	return intel_uc_fw_upload(&huc->fw, huc_fw_xfer);
 }
+
+int intel_huc_fw_ggtt_pin(struct intel_huc *huc)
+{
+	struct drm_i915_private *i915 = huc_to_i915(huc);
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	u64 slot = intel_huc_fw_ggtt_offset(huc);
+
+	return intel_uc_fw_ggtt_pin(&huc->fw, ggtt, slot);
+}
+
+void intel_huc_fw_ggtt_unpin(struct intel_huc *huc)
+{
+	struct drm_i915_private *i915 = huc_to_i915(huc);
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	u64 slot = intel_huc_fw_ggtt_offset(huc);
+
+	intel_uc_fw_ggtt_unpin(&huc->fw, ggtt, slot);
+}
+
+u32 intel_huc_fw_ggtt_offset(struct intel_huc *huc)
+{
+	struct drm_i915_private *i915 = huc_to_i915(huc);
+	u32 offset = intel_uc_fw_ggtt_offset(&huc->fw);
+
+	/*
+	 * NOTE: GuC and HuC firmware will share the mm allocation
+	 * range, with GuC filling [range_start, range_start + guc_fw_size).
+	 * The HuC firmware is placed at the next page-aligned slot.
+	 */
+	offset += round_up(i915->guc.fw.size, PAGE_SIZE);
+
+	GEM_BUG_ON(upper_32_bits(offset));
+
+	return offset;
+}
diff --git a/drivers/gpu/drm/i915/intel_huc_fw.h b/drivers/gpu/drm/i915/intel_huc_fw.h
index 8a00a0ebddc5..4d19a61eb3c5 100644
--- a/drivers/gpu/drm/i915/intel_huc_fw.h
+++ b/drivers/gpu/drm/i915/intel_huc_fw.h
@@ -11,5 +11,8 @@ struct intel_huc;
 
 void intel_huc_fw_init_early(struct intel_huc *huc);
 int intel_huc_fw_upload(struct intel_huc *huc);
+int intel_huc_fw_ggtt_pin(struct intel_huc *huc);
+void intel_huc_fw_ggtt_unpin(struct intel_huc *huc);
+u32 intel_huc_fw_ggtt_offset(struct intel_huc *huc);
 
 #endif
diff --git a/drivers/gpu/drm/i915/intel_uc.c b/drivers/gpu/drm/i915/intel_uc.c
index a0728513ae84..df859cd329ed 100644
--- a/drivers/gpu/drm/i915/intel_uc.c
+++ b/drivers/gpu/drm/i915/intel_uc.c
@@ -302,6 +302,7 @@ void intel_uc_fini_misc(struct drm_i915_private *i915)
 int intel_uc_init(struct drm_i915_private *i915)
 {
 	struct intel_guc *guc = &i915->guc;
+	struct intel_huc *huc = &i915->huc;
 	int ret;
 
 	if (!USES_GUC(i915))
@@ -318,19 +319,30 @@ int intel_uc_init(struct drm_i915_private *i915)
 	if (ret)
 		return ret;
 
+	if (USES_HUC(i915)) {
+		ret = intel_huc_init(huc);
+		if (ret)
+			goto err_guc;
+	}
+
 	if (USES_GUC_SUBMISSION(i915)) {
 		/*
 		 * This is stuff we need to have available at fw load time
 		 * if we are planning to enable submission later
 		 */
 		ret = intel_guc_submission_init(guc);
-		if (ret) {
-			intel_guc_fini(guc);
-			return ret;
-		}
+		if (ret)
+			goto err_huc;
 	}
 
 	return 0;
+
+err_huc:
+	if (USES_HUC(i915))
+		intel_huc_fini(huc);
+err_guc:
+	intel_guc_fini(guc);
+	return ret;
 }
 
 void intel_uc_fini(struct drm_i915_private *i915)
@@ -345,6 +357,9 @@ void intel_uc_fini(struct drm_i915_private *i915)
 	if (USES_GUC_SUBMISSION(i915))
 		intel_guc_submission_fini(guc);
 
+	if (USES_HUC(i915))
+		intel_huc_fini(&i915->huc);
+
 	intel_guc_fini(guc);
 }
 
@@ -515,6 +530,32 @@ int intel_uc_suspend(struct drm_i915_private *i915)
 	return 0;
 }
 
+void intel_uc_restore_ggtt_mapping(struct drm_i915_private *i915)
+{
+	struct i915_ggtt *ggtt = &i915->ggtt;
+	struct intel_guc *guc = &i915->guc;
+	u64 slot;
+
+	if (!USES_GUC(i915))
+		return;
+
+	if (guc->fw.fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
+		return;
+
+	slot = intel_guc_fw_ggtt_offset(guc);
+	intel_uc_fw_ggtt_bind(&guc->fw, ggtt, slot);
+
+	if (USES_HUC(i915)) {
+		struct intel_huc *huc = &i915->huc;
+
+		if (huc->fw.fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
+			return;
+
+		slot = intel_huc_fw_ggtt_offset(huc);
+		intel_uc_fw_ggtt_bind(&huc->fw, ggtt, slot);
+	}
+}
+
 int intel_uc_resume(struct drm_i915_private *i915)
 {
 	struct intel_guc *guc = &i915->guc;
diff --git a/drivers/gpu/drm/i915/intel_uc.h b/drivers/gpu/drm/i915/intel_uc.h
index c14729786652..e7e2e871700e 100644
--- a/drivers/gpu/drm/i915/intel_uc.h
+++ b/drivers/gpu/drm/i915/intel_uc.h
@@ -40,6 +40,7 @@ int intel_uc_init(struct drm_i915_private *dev_priv);
 void intel_uc_fini(struct drm_i915_private *dev_priv);
 void intel_uc_reset_prepare(struct drm_i915_private *i915);
 int intel_uc_suspend(struct drm_i915_private *dev_priv);
+void intel_uc_restore_ggtt_mapping(struct drm_i915_private *i915);
 int intel_uc_resume(struct drm_i915_private *dev_priv);
 
 static inline bool intel_uc_is_using_guc(struct drm_i915_private *i915)
diff --git a/drivers/gpu/drm/i915/intel_uc_fw.c b/drivers/gpu/drm/i915/intel_uc_fw.c
index 957c1feb30d3..d979a53fa1ba 100644
--- a/drivers/gpu/drm/i915/intel_uc_fw.c
+++ b/drivers/gpu/drm/i915/intel_uc_fw.c
@@ -201,11 +201,8 @@ void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
  * Return: 0 on success, non-zero on failure.
  */
 int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
-		       int (*xfer)(struct intel_uc_fw *uc_fw,
-				   struct i915_vma *vma))
+		       int (*xfer)(struct intel_uc_fw *uc_fw))
 {
-	struct i915_vma *vma;
-	u32 ggtt_pin_bias;
 	int err;
 
 	DRM_DEBUG_DRIVER("%s fw load %s\n",
@@ -219,33 +216,8 @@ int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
 			 intel_uc_fw_type_repr(uc_fw->type),
 			 intel_uc_fw_status_repr(uc_fw->load_status));
 
-	/* Pin object with firmware */
-	err = i915_gem_object_set_to_gtt_domain(uc_fw->obj, false);
-	if (err) {
-		DRM_DEBUG_DRIVER("%s fw set-domain err=%d\n",
-				 intel_uc_fw_type_repr(uc_fw->type), err);
-		goto fail;
-	}
-
-	ggtt_pin_bias = to_i915(uc_fw->obj->base.dev)->ggtt.pin_bias;
-	vma = i915_gem_object_ggtt_pin(uc_fw->obj, NULL, 0, 0,
-				       PIN_OFFSET_BIAS | ggtt_pin_bias);
-	if (IS_ERR(vma)) {
-		err = PTR_ERR(vma);
-		DRM_DEBUG_DRIVER("%s fw ggtt-pin err=%d\n",
-				 intel_uc_fw_type_repr(uc_fw->type), err);
-		goto fail;
-	}
-
 	/* Call custom loader */
-	err = xfer(uc_fw, vma);
-
-	/*
-	 * 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_vma_unpin(vma);
-
+	err = xfer(uc_fw);
 	if (err)
 		goto fail;
 
@@ -315,3 +287,71 @@ void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p)
 	drm_printf(p, "\tRSA: offset %u, size %u\n",
 		   uc_fw->rsa_offset, uc_fw->rsa_size);
 }
+
+void intel_uc_fw_ggtt_bind(struct intel_uc_fw *uc_fw,
+			   struct i915_ggtt *ggtt, u64 start)
+{
+	struct drm_i915_gem_object *obj = uc_fw->obj;
+	struct i915_vma dummy = {
+		.node = { .start = start, .size = obj->base.size },
+		.pages = obj->mm.pages,
+		.vm = &ggtt->vm,
+	};
+
+	GEM_BUG_ON(!i915_gem_object_has_pinned_pages(obj));
+	ggtt->vm.insert_entries(&ggtt->vm, &dummy, obj->cache_level, 0);
+}
+
+int intel_uc_fw_ggtt_pin(struct intel_uc_fw *uc_fw,
+			 struct i915_ggtt *ggtt, u64 start)
+{
+	struct drm_i915_gem_object *obj = uc_fw->obj;
+	int err;
+
+	if (uc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
+		return -ENOEXEC;
+
+	err = i915_gem_object_pin_pages(obj);
+	if (err) {
+		DRM_DEBUG_DRIVER("%s fw pin-pages err=%d\n",
+				 intel_uc_fw_type_repr(uc_fw->type), err);
+		return err;
+	}
+
+	intel_uc_fw_ggtt_bind(uc_fw, ggtt, start);
+
+	return 0;
+}
+
+void intel_uc_fw_ggtt_unpin(struct intel_uc_fw *uc_fw,
+			    struct i915_ggtt *ggtt, u64 start)
+{
+	struct drm_i915_gem_object *obj = uc_fw->obj;
+	u64 length;
+
+	if (uc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
+		return;
+	
+	length = obj->base.size;
+	ggtt->vm.clear_range(&ggtt->vm, start, length);
+
+	i915_gem_object_unpin_pages(obj);
+}
+
+u32 intel_uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw)
+{
+	struct drm_i915_private *i915;
+	struct drm_mm_node *node;
+
+	if (uc_fw->fetch_status != INTEL_UC_FIRMWARE_SUCCESS)
+		return 0;
+
+	i915 = to_i915(uc_fw->obj->base.dev);
+	node = &i915->ggtt.uc_fw;
+
+	GEM_BUG_ON(!node->allocated);
+	GEM_BUG_ON(upper_32_bits(node->start));
+	GEM_BUG_ON(upper_32_bits(node->start + node->size - 1));
+
+	return lower_32_bits(node->start);
+}
diff --git a/drivers/gpu/drm/i915/intel_uc_fw.h b/drivers/gpu/drm/i915/intel_uc_fw.h
index 854c3a383e07..10ae1bdde3d7 100644
--- a/drivers/gpu/drm/i915/intel_uc_fw.h
+++ b/drivers/gpu/drm/i915/intel_uc_fw.h
@@ -28,6 +28,7 @@
 struct drm_printer;
 struct drm_i915_private;
 struct i915_vma;
+struct i915_ggtt;
 
 /* Home of GuC, HuC and DMC firmwares */
 #define INTEL_UC_FIRMWARE_URL "https://git.kernel.org/pub/scm/linux/kernel/git/firmware/linux-firmware.git/tree/i915"
@@ -146,9 +147,16 @@ static inline u32 intel_uc_fw_get_upload_size(struct intel_uc_fw *uc_fw)
 void intel_uc_fw_fetch(struct drm_i915_private *dev_priv,
 		       struct intel_uc_fw *uc_fw);
 int intel_uc_fw_upload(struct intel_uc_fw *uc_fw,
-		       int (*xfer)(struct intel_uc_fw *uc_fw,
-				   struct i915_vma *vma));
+		       int (*xfer)(struct intel_uc_fw *uc_fw));
+int intel_uc_fw_init(struct intel_uc_fw *uc_fw);
 void intel_uc_fw_fini(struct intel_uc_fw *uc_fw);
 void intel_uc_fw_dump(const struct intel_uc_fw *uc_fw, struct drm_printer *p);
+void intel_uc_fw_ggtt_bind(struct intel_uc_fw *uc_fw,
+			   struct i915_ggtt *ggtt, u64 start);
+int intel_uc_fw_ggtt_pin(struct intel_uc_fw *uc_fw,
+			 struct i915_ggtt *ggtt, u64 start);
+void intel_uc_fw_ggtt_unpin(struct intel_uc_fw *uc_fw,
+			    struct i915_ggtt *ggtt, u64 start);
+u32 intel_uc_fw_ggtt_offset(struct intel_uc_fw *uc_fw);
 
 #endif
-- 
2.19.2



More information about the Intel-gfx-trybot mailing list