Blob Blame History Raw
From b2d6ef70614e9e9dacfa9fc7dac49e7dc22dc8b3 Mon Sep 17 00:00:00 2001
From: Xiong Zhang <xiong.y.zhang@intel.com>
Date: Wed, 8 Nov 2017 00:45:21 +0800
Subject: [PATCH] drm/i915/gvt: Let each vgpu has separate opregion memory
Git-commit: b2d6ef70614e9e9dacfa9fc7dac49e7dc22dc8b3
Patch-mainline: v4.16-rc1
References: FATE#322643 bsc#1055900

Currently every vgpu share a common gvt opregion memory, but
it is freed at vgpu destroy, then the later vgpu doesn't have
opregion memory once the first vgpu is destroyed. This cause
guest function failure like reboot, second or later boot.

This patch allocate and init virt opregion memory for each
vgpu, so this memory could be freed at vgpu destroy.

Signed-off-by: Xiong Zhang <xiong.y.zhang@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
Acked-by: Takashi Iwai <tiwai@suse.de>

---
 drivers/gpu/drm/i915/gvt/gvt.c      |    9 ---
 drivers/gpu/drm/i915/gvt/gvt.h      |   10 ---
 drivers/gpu/drm/i915/gvt/opregion.c |  101 ++++++++++++++----------------------
 3 files changed, 42 insertions(+), 78 deletions(-)

--- a/drivers/gpu/drm/i915/gvt/gvt.c
+++ b/drivers/gpu/drm/i915/gvt/gvt.c
@@ -323,7 +323,6 @@ void intel_gvt_clean_device(struct drm_i
 	intel_gvt_clean_cmd_parser(gvt);
 	intel_gvt_clean_sched_policy(gvt);
 	intel_gvt_clean_workload_scheduler(gvt);
-	intel_gvt_clean_opregion(gvt);
 	intel_gvt_clean_gtt(gvt);
 	intel_gvt_clean_irq(gvt);
 	intel_gvt_clean_mmio_info(gvt);
@@ -397,13 +396,9 @@ int intel_gvt_init_device(struct drm_i91
 	if (ret)
 		goto out_clean_irq;
 
-	ret = intel_gvt_init_opregion(gvt);
-	if (ret)
-		goto out_clean_gtt;
-
 	ret = intel_gvt_init_workload_scheduler(gvt);
 	if (ret)
-		goto out_clean_opregion;
+		goto out_clean_gtt;
 
 	ret = intel_gvt_init_sched_policy(gvt);
 	if (ret)
@@ -460,8 +455,6 @@ out_clean_sched_policy:
 	intel_gvt_clean_sched_policy(gvt);
 out_clean_workload_scheduler:
 	intel_gvt_clean_workload_scheduler(gvt);
-out_clean_opregion:
-	intel_gvt_clean_opregion(gvt);
 out_clean_gtt:
 	intel_gvt_clean_gtt(gvt);
 out_clean_irq:
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -125,7 +125,6 @@ struct intel_vgpu_irq {
 struct intel_vgpu_opregion {
 	void *va;
 	u32 gfn[INTEL_GVT_OPREGION_PAGES];
-	struct page *pages[INTEL_GVT_OPREGION_PAGES];
 };
 
 #define vgpu_opregion(vgpu) (&(vgpu->opregion))
@@ -265,11 +264,6 @@ struct intel_gvt_firmware {
 	bool firmware_loaded;
 };
 
-struct intel_gvt_opregion {
-	void *opregion_va;
-	u32 opregion_pa;
-};
-
 #define NR_MAX_INTEL_VGPU_TYPES 20
 struct intel_vgpu_type {
 	char name[16];
@@ -293,7 +287,6 @@ struct intel_gvt {
 	struct intel_gvt_firmware firmware;
 	struct intel_gvt_irq irq;
 	struct intel_gvt_gtt gtt;
-	struct intel_gvt_opregion opregion;
 	struct intel_gvt_workload_scheduler scheduler;
 	struct notifier_block shadow_ctx_notifier_block[I915_NUM_ENGINES];
 	DECLARE_HASHTABLE(cmd_table, GVT_CMD_HASH_BITS);
@@ -511,9 +504,6 @@ static inline u64 intel_vgpu_get_bar_gpa
 			PCI_BASE_ADDRESS_MEM_MASK;
 }
 
-void intel_gvt_clean_opregion(struct intel_gvt *gvt);
-int intel_gvt_init_opregion(struct intel_gvt *gvt);
-
 void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu);
 int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa);
 
--- a/drivers/gpu/drm/i915/gvt/opregion.c
+++ b/drivers/gpu/drm/i915/gvt/opregion.c
@@ -213,16 +213,55 @@ static void virt_vbt_generation(struct v
 	v->driver_features.lvds_config = BDB_DRIVER_FEATURE_NO_LVDS;
 }
 
+static int alloc_and_init_virt_opregion(struct intel_vgpu *vgpu)
+{
+	u8 *buf;
+	struct opregion_header *header;
+	struct vbt v;
+
+	gvt_dbg_core("init vgpu%d opregion\n", vgpu->id);
+	vgpu_opregion(vgpu)->va = (void *)__get_free_pages(GFP_KERNEL |
+			__GFP_ZERO,
+			get_order(INTEL_GVT_OPREGION_SIZE));
+	if (!vgpu_opregion(vgpu)->va) {
+		gvt_err("fail to get memory for vgpu virt opregion\n");
+		return -ENOMEM;
+	}
+
+	/* emulated opregion with VBT mailbox only */
+	buf = (u8 *)vgpu_opregion(vgpu)->va;
+	header = (struct opregion_header *)buf;
+	memcpy(header->signature, OPREGION_SIGNATURE,
+			sizeof(OPREGION_SIGNATURE));
+	header->size = 0x8;
+	header->opregion_ver = 0x02000000;
+	header->mboxes = MBOX_VBT;
+
+	/* for unknown reason, the value in LID field is incorrect
+	 * which block the windows guest, so workaround it by force
+	 * setting it to "OPEN"
+	 */
+	buf[INTEL_GVT_OPREGION_CLID] = 0x3;
+
+	/* emulated vbt from virt vbt generation */
+	virt_vbt_generation(&v);
+	memcpy(buf + INTEL_GVT_OPREGION_VBT_OFFSET, &v, sizeof(struct vbt));
+
+	return 0;
+}
+
 static int init_vgpu_opregion(struct intel_vgpu *vgpu, u32 gpa)
 {
-	int i;
+	int i, ret;
 
 	if (WARN((vgpu_opregion(vgpu)->va),
 			"vgpu%d: opregion has been initialized already.\n",
 			vgpu->id))
 		return -EINVAL;
 
-	vgpu_opregion(vgpu)->va = vgpu->gvt->opregion.opregion_va;
+	ret = alloc_and_init_virt_opregion(vgpu);
+	if (ret < 0)
+		return ret;
 
 	for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++)
 		vgpu_opregion(vgpu)->gfn[i] = (gpa >> PAGE_SHIFT) + i;
@@ -303,64 +342,6 @@ int intel_vgpu_init_opregion(struct inte
 
 	return 0;
 }
-
-/**
- * intel_gvt_clean_opregion - clean host opergion related stuffs
- * @gvt: a GVT device
- *
- */
-void intel_gvt_clean_opregion(struct intel_gvt *gvt)
-{
-	free_pages((unsigned long)gvt->opregion.opregion_va,
-			get_order(INTEL_GVT_OPREGION_SIZE));
-	gvt->opregion.opregion_va = NULL;
-}
-
-/**
- * intel_gvt_init_opregion - initialize host opergion related stuffs
- * @gvt: a GVT device
- *
- * Returns:
- * Zero on success, negative error code if failed.
- */
-int intel_gvt_init_opregion(struct intel_gvt *gvt)
-{
-	u8 *buf;
-	struct opregion_header *header;
-	struct vbt v;
-
-	gvt_dbg_core("init host opregion\n");
-
-	gvt->opregion.opregion_va = (void *)__get_free_pages(GFP_KERNEL |
-			__GFP_ZERO,
-			get_order(INTEL_GVT_OPREGION_SIZE));
-
-	if (!gvt->opregion.opregion_va) {
-		gvt_err("fail to get memory for virt opregion\n");
-		return -ENOMEM;
-	}
-
-	/* emulated opregion with VBT mailbox only */
-	buf = (u8 *)gvt->opregion.opregion_va;
-	header = (struct opregion_header *)buf;
-	memcpy(header->signature, OPREGION_SIGNATURE,
-			sizeof(OPREGION_SIGNATURE));
-	header->size = 0x8;
-	header->opregion_ver = 0x02000000;
-	header->mboxes = MBOX_VBT;
-
-	/* for unknown reason, the value in LID field is incorrect
-	 * which block the windows guest, so workaround it by force
-	 * setting it to "OPEN"
-	 */
-	buf[INTEL_GVT_OPREGION_CLID] = 0x3;
-
-	/* emulated vbt from virt vbt generation */
-	virt_vbt_generation(&v);
-	memcpy(buf + INTEL_GVT_OPREGION_VBT_OFFSET, &v, sizeof(struct vbt));
-
-	return 0;
-}
 
 #define GVT_OPREGION_FUNC(scic)					\
 	({							\