diff options
author | Xiong Zhang <xiong.y.zhang@intel.com> | 2017-11-08 00:45:21 +0800 |
---|---|---|
committer | Zhenyu Wang <zhenyuw@linux.intel.com> | 2017-11-16 11:48:35 +0800 |
commit | b2d6ef70614e9e9dacfa9fc7dac49e7dc22dc8b3 (patch) | |
tree | d3d9231fb663616dc0fe92e6b82769ec032053d4 /drivers/gpu/drm/i915/gvt/opregion.c | |
parent | 295764cd2ff41e2c1bc8af4050de77cec5e7a1c0 (diff) | |
download | linux-b2d6ef70614e9e9dacfa9fc7dac49e7dc22dc8b3.tar.bz2 |
drm/i915/gvt: Let each vgpu has separate opregion memory
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>
Diffstat (limited to 'drivers/gpu/drm/i915/gvt/opregion.c')
-rw-r--r-- | drivers/gpu/drm/i915/gvt/opregion.c | 101 |
1 files changed, 41 insertions, 60 deletions
diff --git a/drivers/gpu/drm/i915/gvt/opregion.c b/drivers/gpu/drm/i915/gvt/opregion.c index 2533d1ef1c56..80720e59723a 100644 --- 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 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; \ |