Blob Blame History Raw
From 4dff110b15aea2f7653957a70921a7be1f45d59b Mon Sep 17 00:00:00 2001
From: Xiong Zhang <xiong.y.zhang@intel.com>
Date: Mon, 20 Nov 2017 15:31:15 +0800
Subject: [PATCH] drm/i915/gvt: Alloc and Init guest opregion at vgpu creation
Git-commit: 4dff110b15aea2f7653957a70921a7be1f45d59b
Patch-mainline: v4.16-rc1
References: FATE#322643 bsc#1055900

Currently guest opregion is allocated and initialised when guest
write opregion base register. This is too late for kvmgt, so
move it to vgpu_create time.

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

---
 drivers/gpu/drm/i915/gvt/cfg_space.c |    3 -
 drivers/gpu/drm/i915/gvt/gvt.h       |    4 +
 drivers/gpu/drm/i915/gvt/opregion.c  |   90 +++++++++++++++--------------------
 drivers/gpu/drm/i915/gvt/vgpu.c      |    8 ++-
 4 files changed, 53 insertions(+), 52 deletions(-)

--- a/drivers/gpu/drm/i915/gvt/cfg_space.c
+++ b/drivers/gpu/drm/i915/gvt/cfg_space.c
@@ -335,7 +335,8 @@ int intel_vgpu_emulate_cfg_write(struct
 	case INTEL_GVT_PCI_OPREGION:
 		if (WARN_ON(!IS_ALIGNED(offset, 4)))
 			return -EINVAL;
-		ret = intel_vgpu_init_opregion(vgpu, *(u32 *)p_data);
+		ret = intel_vgpu_opregion_base_write_handler(vgpu,
+						   *(u32 *)p_data);
 		if (ret)
 			return ret;
 
--- a/drivers/gpu/drm/i915/gvt/gvt.h
+++ b/drivers/gpu/drm/i915/gvt/gvt.h
@@ -123,6 +123,7 @@ struct intel_vgpu_irq {
 };
 
 struct intel_vgpu_opregion {
+	bool mapped;
 	void *va;
 	u32 gfn[INTEL_GVT_OPREGION_PAGES];
 };
@@ -505,7 +506,8 @@ static inline u64 intel_vgpu_get_bar_gpa
 }
 
 void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu);
-int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa);
+int intel_vgpu_init_opregion(struct intel_vgpu *vgpu);
+int intel_vgpu_opregion_base_write_handler(struct intel_vgpu *vgpu, u32 gpa);
 
 int intel_vgpu_emulate_opregion_request(struct intel_vgpu *vgpu, u32 swsci);
 void populate_pvinfo_page(struct intel_vgpu *vgpu);
--- a/drivers/gpu/drm/i915/gvt/opregion.c
+++ b/drivers/gpu/drm/i915/gvt/opregion.c
@@ -213,7 +213,15 @@ 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)
+/**
+ * intel_vgpu_init_opregion - initialize the stuff used to emulate opregion
+ * @vgpu: a vGPU
+ * @gpa: guest physical address of opregion
+ *
+ * Returns:
+ * Zero on success, negative error code if failed.
+ */
+int intel_vgpu_init_opregion(struct intel_vgpu *vgpu)
 {
 	u8 *buf;
 	struct opregion_header *header;
@@ -251,25 +259,6 @@ static int alloc_and_init_virt_opregion(
 	return 0;
 }
 
-static int init_vgpu_opregion(struct intel_vgpu *vgpu, u32 gpa)
-{
-	int i, ret;
-
-	if (WARN((vgpu_opregion(vgpu)->va),
-			"vgpu%d: opregion has been initialized already.\n",
-			vgpu->id))
-		return -EINVAL;
-
-	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;
-
-	return 0;
-}
-
 static int map_vgpu_opregion(struct intel_vgpu *vgpu, bool map)
 {
 	u64 mfn;
@@ -291,59 +280,62 @@ static int map_vgpu_opregion(struct inte
 			return ret;
 		}
 	}
+
+	vgpu_opregion(vgpu)->mapped = map;
+
 	return 0;
 }
 
 /**
- * intel_vgpu_clean_opregion - clean the stuff used to emulate opregion
+ * intel_vgpu_opregion_base_write_handler - Opregion base register write handler
+ *
  * @vgpu: a vGPU
+ * @gpa: guest physical address of opregion
  *
+ * Returns:
+ * Zero on success, negative error code if failed.
  */
-void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu)
+int intel_vgpu_opregion_base_write_handler(struct intel_vgpu *vgpu, u32 gpa)
 {
-	gvt_dbg_core("vgpu%d: clean vgpu opregion\n", vgpu->id);
-
-	if (!vgpu_opregion(vgpu)->va)
-		return;
+	int i, ret;
 
-	if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_XEN) {
+	/**
+	 * Wins guest on Xengt will write this register twice: xen hvmloader and
+	 * windows graphic driver.
+	 */
+	if (vgpu_opregion(vgpu)->mapped)
 		map_vgpu_opregion(vgpu, false);
-		free_pages((unsigned long)vgpu_opregion(vgpu)->va,
-				get_order(INTEL_GVT_OPREGION_SIZE));
 
-		vgpu_opregion(vgpu)->va = NULL;
-	}
+	for (i = 0; i < INTEL_GVT_OPREGION_PAGES; i++)
+		vgpu_opregion(vgpu)->gfn[i] = (gpa >> PAGE_SHIFT) + i;
+
+	ret = map_vgpu_opregion(vgpu, true);
+
+	return ret;
 }
 
 /**
- * intel_vgpu_init_opregion - initialize the stuff used to emulate opregion
+ * intel_vgpu_clean_opregion - clean the stuff used to emulate opregion
  * @vgpu: a vGPU
- * @gpa: guest physical address of opregion
  *
- * Returns:
- * Zero on success, negative error code if failed.
  */
-int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa)
+void intel_vgpu_clean_opregion(struct intel_vgpu *vgpu)
 {
-	int ret;
-
-	gvt_dbg_core("vgpu%d: init vgpu opregion\n", vgpu->id);
+	gvt_dbg_core("vgpu%d: clean vgpu opregion\n", vgpu->id);
 
-	if (intel_gvt_host.hypervisor_type == INTEL_GVT_HYPERVISOR_XEN) {
-		gvt_dbg_core("emulate opregion from kernel\n");
+	if (!vgpu_opregion(vgpu)->va)
+		return;
 
-		ret = init_vgpu_opregion(vgpu, gpa);
-		if (ret)
-			return ret;
+	if (vgpu_opregion(vgpu)->mapped)
+		map_vgpu_opregion(vgpu, false);
 
-		ret = map_vgpu_opregion(vgpu, true);
-		if (ret)
-			return ret;
-	}
+	free_pages((unsigned long)vgpu_opregion(vgpu)->va,
+			get_order(INTEL_GVT_OPREGION_SIZE));
 
-	return 0;
+	vgpu_opregion(vgpu)->va = NULL;
 }
 
+
 #define GVT_OPREGION_FUNC(scic)					\
 	({							\
 	 u32 __ret;						\
--- a/drivers/gpu/drm/i915/gvt/vgpu.c
+++ b/drivers/gpu/drm/i915/gvt/vgpu.c
@@ -370,10 +370,14 @@ static struct intel_vgpu *__intel_gvt_cr
 	if (ret)
 		goto out_detach_hypervisor_vgpu;
 
-	ret = intel_vgpu_init_display(vgpu, param->resolution);
+	ret = intel_vgpu_init_opregion(vgpu);
 	if (ret)
 		goto out_clean_gtt;
 
+	ret = intel_vgpu_init_display(vgpu, param->resolution);
+	if (ret)
+		goto out_clean_opregion;
+
 	ret = intel_vgpu_setup_submission(vgpu);
 	if (ret)
 		goto out_clean_display;
@@ -396,6 +400,8 @@ out_clean_submission:
 	intel_vgpu_clean_submission(vgpu);
 out_clean_display:
 	intel_vgpu_clean_display(vgpu);
+out_clean_opregion:
+	intel_vgpu_clean_opregion(vgpu);
 out_clean_gtt:
 	intel_vgpu_clean_gtt(vgpu);
 out_detach_hypervisor_vgpu: