drm/i915/gvt: Let each vgpu has separate opregion memory
authorXiong Zhang <xiong.y.zhang@intel.com>
Tue, 7 Nov 2017 16:45:21 +0000 (00:45 +0800)
committerZhenyu Wang <zhenyuw@linux.intel.com>
Thu, 16 Nov 2017 03:48:35 +0000 (11:48 +0800)
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>
drivers/gpu/drm/i915/gvt/gvt.c
drivers/gpu/drm/i915/gvt/gvt.h
drivers/gpu/drm/i915/gvt/opregion.c

index cef06d59884e3cefc289356c96b2207b87ec4fad..3a74a408a96656d9efe852ba924bf79b833670e2 100644 (file)
@@ -323,7 +323,6 @@ void intel_gvt_clean_device(struct drm_i915_private *dev_priv)
        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_i915_private *dev_priv)
        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:
index 27e8186cbc81a81a8c818f30494f8ad41fb8fe63..393066726993e55aacc4e5535f3447d74f033d57 100644 (file)
@@ -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(struct intel_vgpu *vgpu, int bar)
                        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);
 
index 2533d1ef1c5699c936420f338afe03d334d3a95c..80720e59723abfebd4733ebe6456afc649dc03de 100644 (file)
@@ -213,16 +213,55 @@ 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)
+{
+       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;
@@ -304,64 +343,6 @@ int intel_vgpu_init_opregion(struct intel_vgpu *vgpu, u32 gpa)
        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)                                        \
        ({                                                      \
         u32 __ret;                                             \