drm/i915/gvt: Alloc and Init guest opregion at vgpu creation
authorXiong Zhang <xiong.y.zhang@intel.com>
Mon, 20 Nov 2017 07:31:15 +0000 (15:31 +0800)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Mon, 4 Dec 2017 03:24:32 +0000 (11:24 +0800)
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>
drivers/gpu/drm/i915/gvt/cfg_space.c
drivers/gpu/drm/i915/gvt/gvt.h
drivers/gpu/drm/i915/gvt/opregion.c
drivers/gpu/drm/i915/gvt/vgpu.c

index 4ce2e6bd06803138a114ffde419411cd27ca8158..97bfc00d2a8204e46244d477edc57c1483e3f767 100644 (file)
@@ -335,7 +335,8 @@ int intel_vgpu_emulate_cfg_write(struct intel_vgpu *vgpu, unsigned int offset,
        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;
 
index 393066726993e55aacc4e5535f3447d74f033d57..07d3ba0f72776a8a115516a53098a448ff7408a4 100644 (file)
@@ -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(struct intel_vgpu *vgpu, int bar)
 }
 
 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);
index bf8e5c49a64a0e6290430b1671c7eb449a657871..36172f33bd514183bd367324a39236ac9e2604b7 100644 (file)
@@ -213,7 +213,15 @@ static void virt_vbt_generation(struct vbt *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(struct intel_vgpu *vgpu)
        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 intel_vgpu *vgpu, bool map)
                        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;                                             \
index c6b82d1ba7dee0b2f09fc057bde14c248372484d..2896aafc952028f11a80dd022556e355ccd4916a 100644 (file)
@@ -370,10 +370,14 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
        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: