[PATCH v2 3/3] drm/i915/gvt: add VFIO EDID region
Zhenyu Wang
zhenyuw at linux.intel.com
Thu Jan 17 04:57:34 UTC 2019
On 2019.01.16 19:44:27 +0800, hang.yuan at linux.intel.com wrote:
> From: Hang Yuan <hang.yuan at linux.intel.com>
>
> Add EDID region for vGPU and support EDID update via this region.
>
> Signed-off-by: Hang Yuan <hang.yuan at linux.intel.com>
> ---
> drivers/gpu/drm/i915/gvt/gvt.h | 1 +
> drivers/gpu/drm/i915/gvt/hypercall.h | 1 +
> drivers/gpu/drm/i915/gvt/kvmgt.c | 119 +++++++++++++++++++++++++++++++++++
> drivers/gpu/drm/i915/gvt/mpt.h | 17 +++++
> drivers/gpu/drm/i915/gvt/vgpu.c | 6 ++
> 5 files changed, 144 insertions(+)
>
> diff --git a/drivers/gpu/drm/i915/gvt/gvt.h b/drivers/gpu/drm/i915/gvt/gvt.h
> index 8bce09d..54ad341 100644
> --- a/drivers/gpu/drm/i915/gvt/gvt.h
> +++ b/drivers/gpu/drm/i915/gvt/gvt.h
> @@ -203,6 +203,7 @@ struct intel_vgpu {
> struct {
> struct mdev_device *mdev;
> struct vfio_region *region;
> + struct vfio_region_gfx_edid vfio_edid_regs;
> int num_regions;
> struct eventfd_ctx *intx_trigger;
> struct eventfd_ctx *msi_trigger;
> diff --git a/drivers/gpu/drm/i915/gvt/hypercall.h b/drivers/gpu/drm/i915/gvt/hypercall.h
> index 831ab34..4862fb1 100644
> --- a/drivers/gpu/drm/i915/gvt/hypercall.h
> +++ b/drivers/gpu/drm/i915/gvt/hypercall.h
> @@ -67,6 +67,7 @@ struct intel_gvt_mpt {
> int (*set_trap_area)(unsigned long handle, u64 start, u64 end,
> bool map);
> int (*set_opregion)(void *vgpu);
> + int (*set_edid)(void *vgpu, int port_num);
> int (*get_vfio_device)(void *vgpu);
> void (*put_vfio_device)(void *vgpu);
> bool (*is_valid_gfn)(unsigned long handle, unsigned long gfn);
> diff --git a/drivers/gpu/drm/i915/gvt/kvmgt.c b/drivers/gpu/drm/i915/gvt/kvmgt.c
> index 5bec0b5..a667081 100644
> --- a/drivers/gpu/drm/i915/gvt/kvmgt.c
> +++ b/drivers/gpu/drm/i915/gvt/kvmgt.c
> @@ -57,6 +57,8 @@ static const struct intel_gvt_ops *intel_gvt_ops;
> #define VFIO_PCI_INDEX_TO_OFFSET(index) ((u64)(index) << VFIO_PCI_OFFSET_SHIFT)
> #define VFIO_PCI_OFFSET_MASK (((u64)(1) << VFIO_PCI_OFFSET_SHIFT) - 1)
>
> +#define EDID_BLOB_OFFSET (PAGE_SIZE/2)
> +
> #define OPREGION_SIGNATURE "IntelGraphicsMem"
>
> struct vfio_region;
> @@ -427,6 +429,92 @@ static const struct intel_vgpu_regops intel_vgpu_regops_opregion = {
> .release = intel_vgpu_reg_release_opregion,
> };
>
> +static int handle_edid_regs(struct intel_vgpu *vgpu, char *buf, size_t count,
> + u16 offset, bool is_write)
> +{
> + struct vfio_region_gfx_edid *regs = (void *)&vgpu->vdev.vfio_edid_regs;
> +
> + if (offset + count > sizeof(vgpu->vdev.vfio_edid_regs))
> + return -EINVAL;
> +
> + if (count != 4)
> + return -EINVAL;
> +
> + if (is_write) {
> + switch (offset) {
> + case offsetof(struct vfio_region_gfx_edid, link_state):
> + memcpy((char *)regs + offset, buf, count);
> + if (regs->link_state == VFIO_DEVICE_GFX_LINK_STATE_UP)
> + intel_gvt_ops->emulate_hotplug(vgpu, true);
> + else if (regs->link_state
> + == VFIO_DEVICE_GFX_LINK_STATE_DOWN)
> + intel_gvt_ops->emulate_hotplug(vgpu, false);
> + else {
> + gvt_vgpu_err("invalid EDID link state %d\n",
> + regs->link_state);
> + return -EINVAL;
> + }
> + break;
> + default:
> + /* read-only regs */
> + gvt_vgpu_err("write read-only EDID region at offset %d\n",
> + offset);
> + return -EPERM;
> + }
"edid_size" is also writable for user, so need to check or bail with
different error. And we might at least do some validation of passed
edid blob for sanity.
> + } else {
> + memcpy(buf, (char *)regs + offset, count);
> + }
> +
> + return count;
> +}
> +
> +static int handle_edid_blob(struct intel_vgpu *vgpu, char *base, char *buf,
> + size_t count, u16 offset, bool is_write)
> +{
> + if (offset + count > vgpu->vdev.vfio_edid_regs.edid_size)
> + return -EINVAL;
> +
> + if (is_write)
> + memcpy(base + offset, buf, count);
> + else
> + memcpy(buf, base + offset, count);
> +
> + return count;
> +}
> +
> +static size_t intel_vgpu_reg_rw_edid(struct intel_vgpu *vgpu, char *buf,
> + size_t count, loff_t *ppos, bool iswrite)
> +{
> + int ret;
> + unsigned int i = VFIO_PCI_OFFSET_TO_INDEX(*ppos) -
> + VFIO_PCI_NUM_REGIONS;
> + void *base = vgpu->vdev.region[i].data;
> + loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
> +
> + if (pos < EDID_BLOB_OFFSET) {
> + ret = handle_edid_regs(vgpu, buf, count, pos, iswrite);
> + } else {
> + pos -= EDID_BLOB_OFFSET;
> + ret = handle_edid_blob(vgpu, base, buf, count, pos, iswrite);
> + }
> +
> + if (ret < 0)
> + gvt_vgpu_err("failed to access EDID region at offset 0x%llx\n",
> + pos);
> +
> + return ret;
> +}
> +
> +static void intel_vgpu_reg_release_edid(struct intel_vgpu *vgpu,
> + struct vfio_region *region)
> +{
> +}
> +
> +static const struct intel_vgpu_regops intel_vgpu_regops_edid = {
> + .rw = intel_vgpu_reg_rw_edid,
> + .release = intel_vgpu_reg_release_edid,
> +};
> +
> static int intel_vgpu_register_reg(struct intel_vgpu *vgpu,
> unsigned int type, unsigned int subtype,
> const struct intel_vgpu_regops *ops,
> @@ -493,6 +581,36 @@ static int kvmgt_set_opregion(void *p_vgpu)
> return ret;
> }
>
> +static int kvmgt_set_edid(void *p_vgpu, int port_num)
> +{
> + struct intel_vgpu *vgpu = (struct intel_vgpu *)p_vgpu;
> + struct intel_vgpu_port *port = intel_vgpu_port(vgpu, port_num);
> + void *base;
> + int ret;
> +
> + base = port->edid->edid_block;
> + if (!base)
> + return -ENOMEM;
> +
> + vgpu->vdev.vfio_edid_regs.edid_offset = EDID_BLOB_OFFSET;
> +
> + /* No extended EDID block for DP interface */
> + vgpu->vdev.vfio_edid_regs.edid_max_size = EDID_SIZE;
> + vgpu->vdev.vfio_edid_regs.edid_size = EDID_SIZE;
> + vgpu->vdev.vfio_edid_regs.max_xres = vgpu_edid_xres(port->id);
> + vgpu->vdev.vfio_edid_regs.max_yres = vgpu_edid_yres(port->id);
> +
> + ret = intel_vgpu_register_reg(vgpu,
> + VFIO_REGION_TYPE_GFX,
> + VFIO_REGION_SUBTYPE_GFX_EDID,
> + &intel_vgpu_regops_edid, EDID_SIZE,
> + VFIO_REGION_INFO_FLAG_READ |
> + VFIO_REGION_INFO_FLAG_WRITE |
> + VFIO_REGION_INFO_FLAG_CAPS, base);
> +
> + return ret;
> +}
> +
> static void kvmgt_put_vfio_device(void *vgpu)
> {
> if (WARN_ON(!((struct intel_vgpu *)vgpu)->vdev.vfio_device))
> @@ -1896,6 +2014,7 @@ static struct intel_gvt_mpt kvmgt_mpt = {
> .dma_map_guest_page = kvmgt_dma_map_guest_page,
> .dma_unmap_guest_page = kvmgt_dma_unmap_guest_page,
> .set_opregion = kvmgt_set_opregion,
> + .set_edid = kvmgt_set_edid,
> .get_vfio_device = kvmgt_get_vfio_device,
> .put_vfio_device = kvmgt_put_vfio_device,
> .is_valid_gfn = kvmgt_is_valid_gfn,
> diff --git a/drivers/gpu/drm/i915/gvt/mpt.h b/drivers/gpu/drm/i915/gvt/mpt.h
> index 5b5995a..0f94401 100644
> --- a/drivers/gpu/drm/i915/gvt/mpt.h
> +++ b/drivers/gpu/drm/i915/gvt/mpt.h
> @@ -314,6 +314,23 @@ static inline int intel_gvt_hypervisor_set_opregion(struct intel_vgpu *vgpu)
> }
>
> /**
> + * intel_gvt_hypervisor_set_edid - Set EDID region for guest
> + * @vgpu: a vGPU
> + * @port_num: display port number
> + *
> + * Returns:
> + * Zero on success, negative error code if failed.
> + */
> +static inline int intel_gvt_hypervisor_set_edid(struct intel_vgpu *vgpu,
> + int port_num)
> +{
> + if (!intel_gvt_host.mpt->set_edid)
> + return 0;
> +
> + return intel_gvt_host.mpt->set_edid(vgpu, port_num);
> +}
> +
> +/**
> * intel_gvt_hypervisor_get_vfio_device - increase vfio device ref count
> * @vgpu: a vGPU
> *
> diff --git a/drivers/gpu/drm/i915/gvt/vgpu.c b/drivers/gpu/drm/i915/gvt/vgpu.c
> index e1c860f8..720e2b1 100644
> --- a/drivers/gpu/drm/i915/gvt/vgpu.c
> +++ b/drivers/gpu/drm/i915/gvt/vgpu.c
> @@ -428,6 +428,12 @@ static struct intel_vgpu *__intel_gvt_create_vgpu(struct intel_gvt *gvt,
> if (ret)
> goto out_clean_sched_policy;
>
> + /*TODO: add more platforms support */
> + if (IS_SKYLAKE(gvt->dev_priv) || IS_KABYLAKE(gvt->dev_priv))
> + ret = intel_gvt_hypervisor_set_edid(vgpu, PORT_D);
> + if (ret)
> + goto out_clean_sched_policy;
> +
> return vgpu;
>
> out_clean_sched_policy:
> --
> 2.7.4
>
> _______________________________________________
> intel-gvt-dev mailing list
> intel-gvt-dev at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gvt-dev
--
Open Source Technology Center, Intel ltd.
$gpg --keyserver wwwkeys.pgp.net --recv-keys 4D781827
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 195 bytes
Desc: not available
URL: <https://lists.freedesktop.org/archives/intel-gvt-dev/attachments/20190117/0956abe8/attachment.sig>
More information about the intel-gvt-dev
mailing list