clear-pkgs-linux-iot-lts2018/0601-drm-i915-gvt-implement...

351 lines
12 KiB
Diff

From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Pei Zhang <pei.zhang@intel.com>
Date: Fri, 14 Sep 2018 16:10:19 +0800
Subject: [PATCH] drm/i915/gvt: implement pvmmio in GVTg
If pvmmio is enabled in i915 host driver, guest i915 will read most MMIO
register directly, which won't be trapped to host GVT. A small range
MMIOs still need trap. They are filtered in a static function, and this
patch is to implement the handler of these registers in GVTg.
Also, when pvmmio is enabled, we will optimize ELSP port writing, to
reduce the mmio trap numbers from 4 to 1, which can improve the guest GPU
performance.
Change-Id: Ic72a87499baabe9b3b2fbb5ad827e6ae062ff959
Signed-off-by: Pei Zhang <pei.zhang@intel.com>
Acknowledged-by: Singh, Satyeshwar <satyeshwar.singh@intel.com>
Reviewed-on:
Reviewed-by: He, Min <min.he@intel.com>
Reviewed-by: Jiang, Fei <fei.jiang@intel.com>
Reviewed-by: Dong, Eddie <eddie.dong@intel.com>
Tested-by: Dong, Eddie <eddie.dong@intel.com>
---
drivers/gpu/drm/i915/gvt/acrngt.c | 92 ++++++++++++++++++++++++++++
drivers/gpu/drm/i915/gvt/handlers.c | 75 ++++++++++++++++++++---
drivers/gpu/drm/i915/gvt/hypercall.h | 2 +
drivers/gpu/drm/i915/gvt/mpt.h | 21 +++++++
drivers/gpu/drm/i915/gvt/vgpu.c | 4 ++
5 files changed, 186 insertions(+), 8 deletions(-)
diff --git a/drivers/gpu/drm/i915/gvt/acrngt.c b/drivers/gpu/drm/i915/gvt/acrngt.c
index 346a676d77bc..c6fff10a1679 100644
--- a/drivers/gpu/drm/i915/gvt/acrngt.c
+++ b/drivers/gpu/drm/i915/gvt/acrngt.c
@@ -838,6 +838,97 @@ static int acrngt_set_trap_area(unsigned long handle, u64 start,
return ret;
}
+static int acrngt_set_pvmmio(unsigned long handle, u64 start, u64 end, bool map)
+{
+ int rc, i;
+ unsigned long mfn, shared_mfn;
+ unsigned long pfn = start >> PAGE_SHIFT;
+ u32 mmio_size_fn = acrngt_priv.gvt->device_info.mmio_size >> PAGE_SHIFT;
+ struct acrngt_hvm_dev *info = (struct acrngt_hvm_dev *)handle;
+
+ if (map) {
+ mfn = acrngt_virt_to_mfn(info->vgpu->mmio.vreg);
+ rc = acrngt_map_gfn_to_mfn(handle, pfn, mfn, mmio_size_fn, map);
+ if (rc) {
+ gvt_err("acrn-gvt: map pfn %lx to mfn %lx fail with ret %d\n",
+ pfn, mfn, rc);
+ return rc;
+ }
+
+ /* map the shared page to guest */
+ shared_mfn = acrngt_virt_to_mfn(info->vgpu->mmio.shared_page);
+ rc = acrngt_map_gfn_to_mfn(handle, pfn + mmio_size_fn, shared_mfn, 1, map);
+ if (rc) {
+ gvt_err("acrn-gvt: map shared page fail with ret %d\n", rc);
+ return rc;
+ }
+
+ /* mmio access is trapped like memory write protection */
+ rc = acrn_ioreq_add_iorange(info->client, REQ_WP, pfn << PAGE_SHIFT,
+ ((pfn + mmio_size_fn) << PAGE_SHIFT) - 1);
+ if (rc) {
+ gvt_err("failed acrn_ioreq_add_iorange for pfn 0x%lx\n", pfn);
+ return rc;
+ }
+
+ for (i = 0; i < mmio_size_fn; i++) {
+ rc = write_protect_page(info->vm_id,
+ (pfn + i) << PAGE_SHIFT, true);
+ if (rc) {
+ gvt_err("failed set wp for pfn 0x%lx\n", pfn + i);
+ return rc;
+ }
+ }
+
+ /* scratch reg access is trapped like mmio access, 1 page */
+ rc = acrngt_map_gfn_to_mfn(handle, pfn + (VGT_PVINFO_PAGE >> PAGE_SHIFT),
+ mfn + (VGT_PVINFO_PAGE >> PAGE_SHIFT), 1, 0);
+ if (rc) {
+ gvt_err("acrn-gvt: map pfn %lx to mfn %lx fail with ret %d\n",
+ pfn, mfn, rc);
+ return rc;
+ }
+ rc = acrn_ioreq_add_iorange(info->client, REQ_MMIO,
+ (pfn << PAGE_SHIFT) + VGT_PVINFO_PAGE,
+ ((pfn + 1) << PAGE_SHIFT) + VGT_PVINFO_PAGE - 1);
+ if (rc) {
+ gvt_err("failed acrn_ioreq_add_iorange for pfn 0x%lx\n",
+ (pfn << PAGE_SHIFT) + VGT_PVINFO_PAGE);
+ return rc;
+ }
+
+ } else {
+ mfn = acrngt_virt_to_mfn(info->vgpu->mmio.vreg);
+ rc = acrngt_map_gfn_to_mfn(handle, pfn, mfn, mmio_size_fn, map);
+ if (rc) {
+ gvt_err("acrn-gvt: map pfn %lx to mfn %lx fail with ret %d\n",
+ pfn, mfn, rc);
+ return rc;
+ }
+ rc = acrn_ioreq_del_iorange(info->client, REQ_WP, pfn << PAGE_SHIFT,
+ ((pfn + mmio_size_fn) << PAGE_SHIFT) - 1);
+ if (rc) {
+ gvt_err("failed acrn_ioreq_add_iorange for pfn 0x%lx\n", pfn);
+ return rc;
+ }
+ rc = acrn_ioreq_add_iorange(info->client, REQ_MMIO, pfn << PAGE_SHIFT,
+ ((pfn + mmio_size_fn) << PAGE_SHIFT) - 1);
+ if (rc) {
+ gvt_err("failed acrn_ioreq_del_iorange for pfn 0x%lx\n", pfn);
+ return rc;
+ }
+
+ /* unmap the shared page to guest */
+ shared_mfn = acrngt_virt_to_mfn(info->vgpu->mmio.shared_page);
+ rc = acrngt_map_gfn_to_mfn(handle, pfn + mmio_size_fn, shared_mfn, 1, map);
+ if (rc) {
+ gvt_err("acrn-gvt: map shared page fail with ret %d\n", rc);
+ return rc;
+ }
+ }
+ return rc;
+}
+
static int acrngt_dom0_ready(void)
{
char *env[] = {"GVT_DOM0_READY=1", NULL};
@@ -880,6 +971,7 @@ struct intel_gvt_mpt acrn_gvt_mpt = {
.dma_map_guest_page = acrngt_dma_map_guest_page,
.dma_unmap_guest_page = acrngt_dma_unmap_guest_page,
.set_trap_area = acrngt_set_trap_area,
+ .set_pvmmio = acrngt_set_pvmmio,
.dom0_ready = acrngt_dom0_ready,
};
EXPORT_SYMBOL_GPL(acrn_gvt_mpt);
diff --git a/drivers/gpu/drm/i915/gvt/handlers.c b/drivers/gpu/drm/i915/gvt/handlers.c
index 88d34ef2c057..14a75c6dff4d 100644
--- a/drivers/gpu/drm/i915/gvt/handlers.c
+++ b/drivers/gpu/drm/i915/gvt/handlers.c
@@ -1145,6 +1145,7 @@ static int pvinfo_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
void *p_data, unsigned int bytes)
{
bool invalid_read = false;
+ int ret = 0;
read_vreg(vgpu, offset, p_data, bytes);
@@ -1159,9 +1160,27 @@ static int pvinfo_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
_vgtif_reg(avail_rs.fence_num) + 4)
invalid_read = true;
break;
+ case _vgtif_reg(pv_mmio):
+ /* a remap happens from guest mmio read operation, the target reg offset
+ * is in the first DWORD of shared_page.
+ */
+ {
+ u32 reg = vgpu->mmio.shared_page->reg_addr;
+ struct intel_gvt_mmio_info *mmio;
+
+ mmio = find_mmio_info(vgpu->gvt, rounddown(reg, 4));
+ if (mmio)
+ ret = mmio->read(vgpu, reg, p_data, bytes);
+ else
+ ret = intel_vgpu_default_mmio_read(vgpu, reg, p_data,
+ bytes);
+ break;
+ }
+
case 0x78010: /* vgt_caps */
case 0x7881c:
case _vgtif_reg(scaler_owned):
+ case _vgtif_reg(enable_pvmmio):
break;
default:
invalid_read = true;
@@ -1171,7 +1190,7 @@ static int pvinfo_mmio_read(struct intel_vgpu *vgpu, unsigned int offset,
gvt_vgpu_err("invalid pvinfo read: [%x:%x] = %x\n",
offset, bytes, *(u32 *)p_data);
vgpu->pv_notified = true;
- return 0;
+ return ret;
}
static int handle_g2v_notification(struct intel_vgpu *vgpu, int notification)
@@ -1219,6 +1238,26 @@ static int send_display_ready_uevent(struct intel_vgpu *vgpu, int ready)
return kobject_uevent_env(kobj, KOBJ_ADD, env);
}
+#define INTEL_GVT_PCI_BAR_GTTMMIO 0
+static int set_pvmmio(struct intel_vgpu *vgpu, bool map)
+{
+ u64 start, end;
+ u64 val;
+ int ret;
+
+ val = vgpu_cfg_space(vgpu)[PCI_BASE_ADDRESS_0];
+ if (val & PCI_BASE_ADDRESS_MEM_TYPE_64)
+ start = *(u64 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
+ else
+ start = *(u32 *)(vgpu_cfg_space(vgpu) + PCI_BASE_ADDRESS_0);
+
+ start &= ~GENMASK(3, 0);
+ end = start + vgpu->cfg_space.bar[INTEL_GVT_PCI_BAR_GTTMMIO].size - 1;
+
+ ret = intel_gvt_hypervisor_set_pvmmio(vgpu, start, end, map);
+ return ret;
+}
+
static int pvinfo_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
void *p_data, unsigned int bytes)
{
@@ -1235,6 +1274,18 @@ static int pvinfo_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
case _vgtif_reg(g2v_notify):
ret = handle_g2v_notification(vgpu, data);
break;
+ case _vgtif_reg(enable_pvmmio):
+ if (i915_modparams.enable_pvmmio) {
+ vgpu_vreg(vgpu, offset) = data &
+ i915_modparams.enable_pvmmio;
+ if (set_pvmmio(vgpu, !!vgpu_vreg(vgpu, offset))) {
+ vgpu_vreg(vgpu, offset) = 0;
+ break;
+ }
+ } else {
+ vgpu_vreg(vgpu, offset) = 0;
+ }
+ break;
/* add xhot and yhot to handled list to avoid error log */
case _vgtif_reg(cursor_x_hot):
case _vgtif_reg(cursor_y_hot):
@@ -1628,6 +1679,7 @@ static int elsp_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
int ring_id = intel_gvt_render_mmio_to_ring_id(vgpu->gvt, offset);
struct intel_vgpu_execlist *execlist;
u32 data = *(u32 *)p_data;
+ u32 *elsp_data = vgpu->mmio.shared_page->elsp_data;
int ret = 0;
if (WARN_ON(ring_id < 0 || ring_id >= I915_NUM_ENGINES))
@@ -1635,16 +1687,23 @@ static int elsp_mmio_write(struct intel_vgpu *vgpu, unsigned int offset,
execlist = &vgpu->submission.execlist[ring_id];
- execlist->elsp_dwords.data[3 - execlist->elsp_dwords.index] = data;
- if (execlist->elsp_dwords.index == 3) {
+ if (VGPU_PVMMIO(vgpu) & PVMMIO_ELSP_SUBMIT) {
+ execlist->elsp_dwords.data[3] = elsp_data[0];
+ execlist->elsp_dwords.data[2] = elsp_data[1];
+ execlist->elsp_dwords.data[1] = elsp_data[2];
+ execlist->elsp_dwords.data[0] = data;
ret = intel_vgpu_submit_execlist(vgpu, ring_id);
- if(ret)
- gvt_vgpu_err("fail submit workload on ring %d\n",
- ring_id);
+ } else {
+ execlist->elsp_dwords.data[3 - execlist->elsp_dwords.index] = data;
+ if (execlist->elsp_dwords.index == 3)
+ ret = intel_vgpu_submit_execlist(vgpu, ring_id);
+ ++execlist->elsp_dwords.index;
+ execlist->elsp_dwords.index &= 0x3;
}
- ++execlist->elsp_dwords.index;
- execlist->elsp_dwords.index &= 0x3;
+ if (ret)
+ gvt_vgpu_err("fail submit workload on ring %d\n", ring_id);
+
return ret;
}
diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h
index d4b7929c8bee..4c550627e78e 100644
--- a/drivers/gpu/drm/i915/gvt/hypercall.h
+++ b/drivers/gpu/drm/i915/gvt/hypercall.h
@@ -60,6 +60,8 @@ struct intel_gvt_mpt {
unsigned long mfn, unsigned int nr, bool map);
int (*set_trap_area)(unsigned long handle, u64 start, u64 end,
bool map);
+ int (*set_pvmmio)(unsigned long handle, u64 start, u64 end,
+ bool map);
int (*set_opregion)(void *vgpu);
int (*get_vfio_device)(void *vgpu);
void (*put_vfio_device)(void *vgpu);
diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
index feed7adb6fde..6eef2e01e46a 100644
--- a/drivers/gpu/drm/i915/gvt/mpt.h
+++ b/drivers/gpu/drm/i915/gvt/mpt.h
@@ -300,6 +300,27 @@ static inline int intel_gvt_hypervisor_set_trap_area(
return intel_gvt_host.mpt->set_trap_area(vgpu->handle, start, end, map);
}
+/**
+ * intel_gvt_hypervisor_set_pvmmio - Set the pvmmio area
+ * @vgpu: a vGPU
+ * @start: the beginning of the guest physical address region
+ * @end: the end of the guest physical address region
+ * @map: map or unmap
+ *
+ * Returns:
+ * Zero on success, negative error code if failed.
+ */
+static inline int intel_gvt_hypervisor_set_pvmmio(
+ struct intel_vgpu *vgpu, u64 start, u64 end, bool map)
+{
+ /* a MPT implementation could have MMIO trapped elsewhere */
+ if (!intel_gvt_host.mpt->set_pvmmio)
+ return -ENOENT;
+
+ return intel_gvt_host.mpt->set_pvmmio(vgpu->handle, start, end, map);
+}
+
+
/**
* intel_gvt_hypervisor_set_opregion - Set opregion for guest
* @vgpu: a vGPU
diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c
index 01d5e133e471..d4c20295bee3 100644
--- a/drivers/gpu/drm/i915/gvt/vgpu.c
+++ b/drivers/gpu/drm/i915/gvt/vgpu.c
@@ -75,6 +75,8 @@ void populate_pvinfo_page(struct intel_vgpu *vgpu)
vgpu_vreg_t(vgpu, vgtif_reg(scaler_owned)) |=
1 << (pipe * SKL_NUM_SCALERS + scaler);
+ vgpu_vreg_t(vgpu, vgtif_reg(enable_pvmmio)) = 0;
+
gvt_dbg_core("Populate PVINFO PAGE for vGPU %d\n", vgpu->id);
gvt_dbg_core("aperture base [GMADR] 0x%llx size 0x%llx\n",
vgpu_aperture_gmadr_base(vgpu), vgpu_aperture_sz(vgpu));
@@ -546,6 +548,7 @@ void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
unsigned int resetting_eng = dmlr ? ALL_ENGINES : engine_mask;
enum intel_engine_id i;
struct intel_engine_cs *engine;
+ bool enable_pvmmio = vgpu_vreg_t(vgpu, vgtif_reg(enable_pvmmio));
gvt_dbg_core("------------------------------------------\n");
gvt_dbg_core("resseting vgpu%d, dmlr %d, engine_mask %08x\n",
@@ -580,6 +583,7 @@ void intel_gvt_reset_vgpu_locked(struct intel_vgpu *vgpu, bool dmlr,
intel_vgpu_reset_mmio(vgpu, dmlr);
populate_pvinfo_page(vgpu);
+ vgpu_vreg_t(vgpu, vgtif_reg(enable_pvmmio)) = enable_pvmmio;
if (dmlr) {
intel_vgpu_reset_display(vgpu);
--
https://clearlinux.org