drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
/*
|
|
|
|
|
* KVMGT - the implementation of Intel mediated pass-through framework for KVM
|
|
|
|
|
*
|
2022-04-11 16:13:58 +02:00
|
|
|
* Copyright(c) 2011-2016 Intel Corporation. All rights reserved.
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
*
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
|
|
|
* to deal in the Software without restriction, including without limitation
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
|
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
|
|
|
*
|
|
|
|
|
* The above copyright notice and this permission notice (including the next
|
|
|
|
|
* paragraph) shall be included in all copies or substantial portions of the
|
|
|
|
|
* Software.
|
|
|
|
|
*
|
|
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
|
|
|
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
|
|
|
* SOFTWARE.
|
|
|
|
|
*
|
|
|
|
|
* Authors:
|
|
|
|
|
* Kevin Tian <kevin.tian@intel.com>
|
|
|
|
|
* Jike Song <jike.song@intel.com>
|
|
|
|
|
* Xiaoguang Chen <xiaoguang.chen@intel.com>
|
2022-04-11 16:13:58 +02:00
|
|
|
* Eddie Dong <eddie.dong@intel.com>
|
|
|
|
|
*
|
|
|
|
|
* Contributors:
|
|
|
|
|
* Niu Bing <bing.niu@intel.com>
|
|
|
|
|
* Zhi Wang <zhi.a.wang@intel.com>
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
|
#include <linux/device.h>
|
|
|
|
|
#include <linux/mm.h>
|
2020-06-10 18:41:59 -07:00
|
|
|
#include <linux/kthread.h>
|
2018-08-31 10:58:52 +08:00
|
|
|
#include <linux/sched/mm.h>
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
#include <linux/types.h>
|
|
|
|
|
#include <linux/list.h>
|
|
|
|
|
#include <linux/rbtree.h>
|
|
|
|
|
#include <linux/spinlock.h>
|
|
|
|
|
#include <linux/eventfd.h>
|
|
|
|
|
#include <linux/uuid.h>
|
2016-12-08 11:00:36 +08:00
|
|
|
#include <linux/mdev.h>
|
2018-03-05 15:30:34 +08:00
|
|
|
#include <linux/debugfs.h>
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2018-08-02 22:40:19 -05:00
|
|
|
#include <linux/nospec.h>
|
|
|
|
|
|
2022-02-15 14:20:30 +02:00
|
|
|
#include <drm/drm_edid.h>
|
|
|
|
|
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
#include "i915_drv.h"
|
2022-04-11 16:13:35 +02:00
|
|
|
#include "intel_gvt.h"
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
#include "gvt.h"
|
|
|
|
|
|
2022-04-11 16:13:35 +02:00
|
|
|
MODULE_IMPORT_NS(DMA_BUF);
|
|
|
|
|
MODULE_IMPORT_NS(I915_GVT);
|
|
|
|
|
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
/* helper macros copied from vfio-pci */
|
|
|
|
|
#define VFIO_PCI_OFFSET_SHIFT 40
|
|
|
|
|
#define VFIO_PCI_OFFSET_TO_INDEX(off) (off >> VFIO_PCI_OFFSET_SHIFT)
|
|
|
|
|
#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)
|
|
|
|
|
|
2019-01-30 18:25:54 +08:00
|
|
|
#define EDID_BLOB_OFFSET (PAGE_SIZE/2)
|
|
|
|
|
|
2017-11-20 15:31:16 +08:00
|
|
|
#define OPREGION_SIGNATURE "IntelGraphicsMem"
|
|
|
|
|
|
|
|
|
|
struct vfio_region;
|
|
|
|
|
struct intel_vgpu_regops {
|
|
|
|
|
size_t (*rw)(struct intel_vgpu *vgpu, char *buf,
|
|
|
|
|
size_t count, loff_t *ppos, bool iswrite);
|
|
|
|
|
void (*release)(struct intel_vgpu *vgpu,
|
|
|
|
|
struct vfio_region *region);
|
|
|
|
|
};
|
|
|
|
|
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
struct vfio_region {
|
|
|
|
|
u32 type;
|
|
|
|
|
u32 subtype;
|
|
|
|
|
size_t size;
|
|
|
|
|
u32 flags;
|
2017-11-20 15:31:16 +08:00
|
|
|
const struct intel_vgpu_regops *ops;
|
|
|
|
|
void *data;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
};
|
|
|
|
|
|
2019-01-30 18:25:54 +08:00
|
|
|
struct vfio_edid_region {
|
|
|
|
|
struct vfio_region_gfx_edid vfio_edid_regs;
|
|
|
|
|
void *edid_blob;
|
|
|
|
|
};
|
|
|
|
|
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
struct kvmgt_pgfn {
|
|
|
|
|
gfn_t gfn;
|
|
|
|
|
struct hlist_node hnode;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct gvt_dma {
|
2018-03-01 15:49:59 +08:00
|
|
|
struct intel_vgpu *vgpu;
|
|
|
|
|
struct rb_node gfn_node;
|
|
|
|
|
struct rb_node dma_addr_node;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
gfn_t gfn;
|
2018-03-01 15:49:59 +08:00
|
|
|
dma_addr_t dma_addr;
|
2018-05-15 10:35:42 +08:00
|
|
|
unsigned long size;
|
2018-03-01 15:49:59 +08:00
|
|
|
struct kref ref;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
};
|
|
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
#define vfio_dev_to_vgpu(vfio_dev) \
|
|
|
|
|
container_of((vfio_dev), struct intel_vgpu, vfio_device)
|
|
|
|
|
|
2022-04-11 16:13:56 +02:00
|
|
|
static void kvmgt_page_track_write(struct kvm_vcpu *vcpu, gpa_t gpa,
|
|
|
|
|
const u8 *val, int len,
|
|
|
|
|
struct kvm_page_track_notifier_node *node);
|
|
|
|
|
static void kvmgt_page_track_flush_slot(struct kvm *kvm,
|
|
|
|
|
struct kvm_memory_slot *slot,
|
|
|
|
|
struct kvm_page_track_notifier_node *node);
|
|
|
|
|
|
2021-05-13 16:39:02 +08:00
|
|
|
static ssize_t available_instances_show(struct mdev_type *mtype,
|
|
|
|
|
struct mdev_type_attribute *attr,
|
|
|
|
|
char *buf)
|
|
|
|
|
{
|
|
|
|
|
struct intel_vgpu_type *type;
|
|
|
|
|
unsigned int num = 0;
|
|
|
|
|
struct intel_gvt *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt;
|
|
|
|
|
|
|
|
|
|
type = &gvt->types[mtype_get_type_group_id(mtype)];
|
|
|
|
|
if (!type)
|
|
|
|
|
num = 0;
|
|
|
|
|
else
|
|
|
|
|
num = type->avail_instance;
|
|
|
|
|
|
|
|
|
|
return sprintf(buf, "%u\n", num);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t device_api_show(struct mdev_type *mtype,
|
|
|
|
|
struct mdev_type_attribute *attr, char *buf)
|
|
|
|
|
{
|
|
|
|
|
return sprintf(buf, "%s\n", VFIO_DEVICE_API_PCI_STRING);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ssize_t description_show(struct mdev_type *mtype,
|
|
|
|
|
struct mdev_type_attribute *attr, char *buf)
|
|
|
|
|
{
|
|
|
|
|
struct intel_vgpu_type *type;
|
|
|
|
|
struct intel_gvt *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt;
|
|
|
|
|
|
|
|
|
|
type = &gvt->types[mtype_get_type_group_id(mtype)];
|
|
|
|
|
if (!type)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return sprintf(buf, "low_gm_size: %dMB\nhigh_gm_size: %dMB\n"
|
|
|
|
|
"fence: %d\nresolution: %s\n"
|
|
|
|
|
"weight: %d\n",
|
|
|
|
|
BYTES_TO_MB(type->low_gm_size),
|
|
|
|
|
BYTES_TO_MB(type->high_gm_size),
|
|
|
|
|
type->fence, vgpu_edid_str(type->resolution),
|
|
|
|
|
type->weight);
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-22 10:05:32 -05:00
|
|
|
static ssize_t name_show(struct mdev_type *mtype,
|
|
|
|
|
struct mdev_type_attribute *attr, char *buf)
|
|
|
|
|
{
|
|
|
|
|
struct intel_vgpu_type *type;
|
|
|
|
|
struct intel_gvt *gvt = kdev_to_i915(mtype_get_parent_dev(mtype))->gvt;
|
|
|
|
|
|
|
|
|
|
type = &gvt->types[mtype_get_type_group_id(mtype)];
|
|
|
|
|
if (!type)
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
return sprintf(buf, "%s\n", type->name);
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-13 16:39:02 +08:00
|
|
|
static MDEV_TYPE_ATTR_RO(available_instances);
|
|
|
|
|
static MDEV_TYPE_ATTR_RO(device_api);
|
|
|
|
|
static MDEV_TYPE_ATTR_RO(description);
|
2022-02-22 10:05:32 -05:00
|
|
|
static MDEV_TYPE_ATTR_RO(name);
|
2021-05-13 16:39:02 +08:00
|
|
|
|
|
|
|
|
static struct attribute *gvt_type_attrs[] = {
|
|
|
|
|
&mdev_type_attr_available_instances.attr,
|
|
|
|
|
&mdev_type_attr_device_api.attr,
|
|
|
|
|
&mdev_type_attr_description.attr,
|
2022-02-22 10:05:32 -05:00
|
|
|
&mdev_type_attr_name.attr,
|
2021-05-13 16:39:02 +08:00
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static struct attribute_group *gvt_vgpu_type_groups[] = {
|
|
|
|
|
[0 ... NR_MAX_INTEL_VGPU_TYPES - 1] = NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-11 16:13:58 +02:00
|
|
|
static int intel_gvt_init_vgpu_type_groups(struct intel_gvt *gvt)
|
2021-05-13 16:39:02 +08:00
|
|
|
{
|
|
|
|
|
int i, j;
|
|
|
|
|
struct intel_vgpu_type *type;
|
|
|
|
|
struct attribute_group *group;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < gvt->num_types; i++) {
|
|
|
|
|
type = &gvt->types[i];
|
|
|
|
|
|
|
|
|
|
group = kzalloc(sizeof(struct attribute_group), GFP_KERNEL);
|
|
|
|
|
if (!group)
|
|
|
|
|
goto unwind;
|
|
|
|
|
|
|
|
|
|
group->name = type->name;
|
|
|
|
|
group->attrs = gvt_type_attrs;
|
|
|
|
|
gvt_vgpu_type_groups[i] = group;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
unwind:
|
|
|
|
|
for (j = 0; j < i; j++) {
|
|
|
|
|
group = gvt_vgpu_type_groups[j];
|
|
|
|
|
kfree(group);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:58 +02:00
|
|
|
static void intel_gvt_cleanup_vgpu_type_groups(struct intel_gvt *gvt)
|
2021-05-13 16:39:02 +08:00
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct attribute_group *group;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < gvt->num_types; i++) {
|
|
|
|
|
group = gvt_vgpu_type_groups[i];
|
|
|
|
|
gvt_vgpu_type_groups[i] = NULL;
|
|
|
|
|
kfree(group);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-05-15 10:35:42 +08:00
|
|
|
static void gvt_unpin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
|
|
|
|
unsigned long size)
|
|
|
|
|
{
|
2020-03-06 10:08:10 +08:00
|
|
|
struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
|
2018-05-15 10:35:42 +08:00
|
|
|
int total_pages;
|
|
|
|
|
int npage;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
total_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE;
|
|
|
|
|
|
|
|
|
|
for (npage = 0; npage < total_pages; npage++) {
|
|
|
|
|
unsigned long cur_gfn = gfn + npage;
|
|
|
|
|
|
2022-05-11 13:12:59 -06:00
|
|
|
ret = vfio_unpin_pages(&vgpu->vfio_device, &cur_gfn, 1);
|
2020-02-20 22:25:07 +05:30
|
|
|
drm_WARN_ON(&i915->drm, ret != 1);
|
2018-05-15 10:35:42 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Pin a normal or compound guest page for dma. */
|
|
|
|
|
static int gvt_pin_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
|
|
|
|
unsigned long size, struct page **page)
|
|
|
|
|
{
|
|
|
|
|
unsigned long base_pfn = 0;
|
|
|
|
|
int total_pages;
|
|
|
|
|
int npage;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
total_pages = roundup(size, PAGE_SIZE) / PAGE_SIZE;
|
|
|
|
|
/*
|
|
|
|
|
* We pin the pages one-by-one to avoid allocating a big arrary
|
|
|
|
|
* on stack to hold pfns.
|
|
|
|
|
*/
|
|
|
|
|
for (npage = 0; npage < total_pages; npage++) {
|
|
|
|
|
unsigned long cur_gfn = gfn + npage;
|
|
|
|
|
unsigned long pfn;
|
|
|
|
|
|
2022-05-11 13:12:59 -06:00
|
|
|
ret = vfio_pin_pages(&vgpu->vfio_device, &cur_gfn, 1,
|
|
|
|
|
IOMMU_READ | IOMMU_WRITE, &pfn);
|
2018-05-15 10:35:42 +08:00
|
|
|
if (ret != 1) {
|
|
|
|
|
gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx, ret %d\n",
|
|
|
|
|
cur_gfn, ret);
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!pfn_valid(pfn)) {
|
|
|
|
|
gvt_vgpu_err("pfn 0x%lx is not mem backed\n", pfn);
|
|
|
|
|
npage++;
|
|
|
|
|
ret = -EFAULT;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (npage == 0)
|
|
|
|
|
base_pfn = pfn;
|
|
|
|
|
else if (base_pfn + npage != pfn) {
|
|
|
|
|
gvt_vgpu_err("The pages are not continuous\n");
|
|
|
|
|
ret = -EINVAL;
|
|
|
|
|
npage++;
|
|
|
|
|
goto err;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*page = pfn_to_page(base_pfn);
|
|
|
|
|
return 0;
|
|
|
|
|
err:
|
|
|
|
|
gvt_unpin_guest_page(vgpu, gfn, npage * PAGE_SIZE);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
static int gvt_dma_map_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
2018-05-15 10:35:42 +08:00
|
|
|
dma_addr_t *dma_addr, unsigned long size)
|
2017-02-09 11:38:01 +08:00
|
|
|
{
|
2021-01-28 14:31:25 +01:00
|
|
|
struct device *dev = vgpu->gvt->gt->i915->drm.dev;
|
2018-05-15 10:35:42 +08:00
|
|
|
struct page *page = NULL;
|
2018-03-01 15:49:59 +08:00
|
|
|
int ret;
|
2017-02-09 11:38:01 +08:00
|
|
|
|
2018-05-15 10:35:42 +08:00
|
|
|
ret = gvt_pin_guest_page(vgpu, gfn, size, &page);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
2017-02-09 11:38:01 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
/* Setup DMA mapping. */
|
2021-09-25 20:46:12 +08:00
|
|
|
*dma_addr = dma_map_page(dev, page, 0, size, DMA_BIDIRECTIONAL);
|
2018-07-19 11:19:21 +03:00
|
|
|
if (dma_mapping_error(dev, *dma_addr)) {
|
2018-05-15 10:35:42 +08:00
|
|
|
gvt_vgpu_err("DMA mapping failed for pfn 0x%lx, ret %d\n",
|
|
|
|
|
page_to_pfn(page), ret);
|
|
|
|
|
gvt_unpin_guest_page(vgpu, gfn, size);
|
2018-07-19 11:19:21 +03:00
|
|
|
return -ENOMEM;
|
2018-03-01 15:49:59 +08:00
|
|
|
}
|
2017-02-09 11:38:01 +08:00
|
|
|
|
2018-07-19 11:19:21 +03:00
|
|
|
return 0;
|
2017-02-09 11:38:01 +08:00
|
|
|
}
|
|
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
static void gvt_dma_unmap_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
2018-05-15 10:35:42 +08:00
|
|
|
dma_addr_t dma_addr, unsigned long size)
|
2017-02-09 11:38:01 +08:00
|
|
|
{
|
2021-01-28 14:31:25 +01:00
|
|
|
struct device *dev = vgpu->gvt->gt->i915->drm.dev;
|
2017-02-09 11:38:01 +08:00
|
|
|
|
2021-09-25 20:46:12 +08:00
|
|
|
dma_unmap_page(dev, dma_addr, size, DMA_BIDIRECTIONAL);
|
2018-05-15 10:35:42 +08:00
|
|
|
gvt_unpin_guest_page(vgpu, gfn, size);
|
2017-02-09 11:38:01 +08:00
|
|
|
}
|
|
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
static struct gvt_dma *__gvt_cache_find_dma_addr(struct intel_vgpu *vgpu,
|
|
|
|
|
dma_addr_t dma_addr)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
2022-04-11 16:13:39 +02:00
|
|
|
struct rb_node *node = vgpu->dma_addr_cache.rb_node;
|
2018-03-01 15:49:59 +08:00
|
|
|
struct gvt_dma *itr;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
|
|
|
|
while (node) {
|
2018-03-01 15:49:59 +08:00
|
|
|
itr = rb_entry(node, struct gvt_dma, dma_addr_node);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
if (dma_addr < itr->dma_addr)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
node = node->rb_left;
|
2018-03-01 15:49:59 +08:00
|
|
|
else if (dma_addr > itr->dma_addr)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
node = node->rb_right;
|
2018-03-01 15:49:59 +08:00
|
|
|
else
|
|
|
|
|
return itr;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
2018-03-01 15:49:59 +08:00
|
|
|
return NULL;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
static struct gvt_dma *__gvt_cache_find_gfn(struct intel_vgpu *vgpu, gfn_t gfn)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
2022-04-11 16:13:39 +02:00
|
|
|
struct rb_node *node = vgpu->gfn_cache.rb_node;
|
2018-03-01 15:49:59 +08:00
|
|
|
struct gvt_dma *itr;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
while (node) {
|
|
|
|
|
itr = rb_entry(node, struct gvt_dma, gfn_node);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
if (gfn < itr->gfn)
|
|
|
|
|
node = node->rb_left;
|
|
|
|
|
else if (gfn > itr->gfn)
|
|
|
|
|
node = node->rb_right;
|
|
|
|
|
else
|
|
|
|
|
return itr;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
2018-03-12 15:12:34 +08:00
|
|
|
static int __gvt_cache_add(struct intel_vgpu *vgpu, gfn_t gfn,
|
2018-05-15 10:35:42 +08:00
|
|
|
dma_addr_t dma_addr, unsigned long size)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
|
|
|
|
struct gvt_dma *new, *itr;
|
2018-03-01 15:49:59 +08:00
|
|
|
struct rb_node **link, *parent = NULL;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
|
|
|
|
new = kzalloc(sizeof(struct gvt_dma), GFP_KERNEL);
|
|
|
|
|
if (!new)
|
2018-03-12 15:12:34 +08:00
|
|
|
return -ENOMEM;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
new->vgpu = vgpu;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
new->gfn = gfn;
|
2018-03-01 15:49:59 +08:00
|
|
|
new->dma_addr = dma_addr;
|
2018-05-15 10:35:42 +08:00
|
|
|
new->size = size;
|
2018-03-01 15:49:59 +08:00
|
|
|
kref_init(&new->ref);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
/* gfn_cache maps gfn to struct gvt_dma. */
|
2022-04-11 16:13:39 +02:00
|
|
|
link = &vgpu->gfn_cache.rb_node;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
while (*link) {
|
|
|
|
|
parent = *link;
|
2018-03-01 15:49:59 +08:00
|
|
|
itr = rb_entry(parent, struct gvt_dma, gfn_node);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
if (gfn < itr->gfn)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
link = &parent->rb_left;
|
|
|
|
|
else
|
|
|
|
|
link = &parent->rb_right;
|
|
|
|
|
}
|
2018-03-01 15:49:59 +08:00
|
|
|
rb_link_node(&new->gfn_node, parent, link);
|
2022-04-11 16:13:39 +02:00
|
|
|
rb_insert_color(&new->gfn_node, &vgpu->gfn_cache);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
/* dma_addr_cache maps dma addr to struct gvt_dma. */
|
|
|
|
|
parent = NULL;
|
2022-04-11 16:13:39 +02:00
|
|
|
link = &vgpu->dma_addr_cache.rb_node;
|
2018-03-01 15:49:59 +08:00
|
|
|
while (*link) {
|
|
|
|
|
parent = *link;
|
|
|
|
|
itr = rb_entry(parent, struct gvt_dma, dma_addr_node);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
if (dma_addr < itr->dma_addr)
|
|
|
|
|
link = &parent->rb_left;
|
|
|
|
|
else
|
|
|
|
|
link = &parent->rb_right;
|
|
|
|
|
}
|
|
|
|
|
rb_link_node(&new->dma_addr_node, parent, link);
|
2022-04-11 16:13:39 +02:00
|
|
|
rb_insert_color(&new->dma_addr_node, &vgpu->dma_addr_cache);
|
2018-03-05 15:30:34 +08:00
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->nr_cache_entries++;
|
2018-03-12 15:12:34 +08:00
|
|
|
return 0;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __gvt_cache_remove_entry(struct intel_vgpu *vgpu,
|
|
|
|
|
struct gvt_dma *entry)
|
|
|
|
|
{
|
2022-04-11 16:13:39 +02:00
|
|
|
rb_erase(&entry->gfn_node, &vgpu->gfn_cache);
|
|
|
|
|
rb_erase(&entry->dma_addr_node, &vgpu->dma_addr_cache);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
kfree(entry);
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->nr_cache_entries--;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void gvt_cache_destroy(struct intel_vgpu *vgpu)
|
|
|
|
|
{
|
|
|
|
|
struct gvt_dma *dma;
|
|
|
|
|
struct rb_node *node = NULL;
|
|
|
|
|
|
2017-06-26 15:20:50 +08:00
|
|
|
for (;;) {
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_lock(&vgpu->cache_lock);
|
|
|
|
|
node = rb_first(&vgpu->gfn_cache);
|
2017-06-26 15:20:50 +08:00
|
|
|
if (!node) {
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_unlock(&vgpu->cache_lock);
|
2017-06-26 15:20:50 +08:00
|
|
|
break;
|
|
|
|
|
}
|
2018-03-01 15:49:59 +08:00
|
|
|
dma = rb_entry(node, struct gvt_dma, gfn_node);
|
2018-05-15 10:35:42 +08:00
|
|
|
gvt_dma_unmap_page(vgpu, dma->gfn, dma->dma_addr, dma->size);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
__gvt_cache_remove_entry(vgpu, dma);
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_unlock(&vgpu->cache_lock);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
static void gvt_cache_init(struct intel_vgpu *vgpu)
|
|
|
|
|
{
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->gfn_cache = RB_ROOT;
|
|
|
|
|
vgpu->dma_addr_cache = RB_ROOT;
|
|
|
|
|
vgpu->nr_cache_entries = 0;
|
|
|
|
|
mutex_init(&vgpu->cache_lock);
|
2018-03-01 15:49:59 +08:00
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:40 +02:00
|
|
|
static void kvmgt_protect_table_init(struct intel_vgpu *info)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
|
|
|
|
hash_init(info->ptable);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:40 +02:00
|
|
|
static void kvmgt_protect_table_destroy(struct intel_vgpu *info)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
|
|
|
|
struct kvmgt_pgfn *p;
|
|
|
|
|
struct hlist_node *tmp;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
hash_for_each_safe(info->ptable, i, tmp, p, hnode) {
|
|
|
|
|
hash_del(&p->hnode);
|
|
|
|
|
kfree(p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct kvmgt_pgfn *
|
2022-04-11 16:13:40 +02:00
|
|
|
__kvmgt_protect_table_find(struct intel_vgpu *info, gfn_t gfn)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
|
|
|
|
struct kvmgt_pgfn *p, *res = NULL;
|
|
|
|
|
|
|
|
|
|
hash_for_each_possible(info->ptable, p, hnode, gfn) {
|
|
|
|
|
if (gfn == p->gfn) {
|
|
|
|
|
res = p;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:40 +02:00
|
|
|
static bool kvmgt_gfn_is_write_protected(struct intel_vgpu *info, gfn_t gfn)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
|
|
|
|
struct kvmgt_pgfn *p;
|
|
|
|
|
|
|
|
|
|
p = __kvmgt_protect_table_find(info, gfn);
|
|
|
|
|
return !!p;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:40 +02:00
|
|
|
static void kvmgt_protect_table_add(struct intel_vgpu *info, gfn_t gfn)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
|
|
|
|
struct kvmgt_pgfn *p;
|
|
|
|
|
|
|
|
|
|
if (kvmgt_gfn_is_write_protected(info, gfn))
|
|
|
|
|
return;
|
|
|
|
|
|
2016-12-08 11:00:34 +08:00
|
|
|
p = kzalloc(sizeof(struct kvmgt_pgfn), GFP_ATOMIC);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
if (WARN(!p, "gfn: 0x%llx\n", gfn))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
p->gfn = gfn;
|
|
|
|
|
hash_add(info->ptable, &p->hnode, gfn);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:40 +02:00
|
|
|
static void kvmgt_protect_table_del(struct intel_vgpu *info, gfn_t gfn)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
|
|
|
|
struct kvmgt_pgfn *p;
|
|
|
|
|
|
|
|
|
|
p = __kvmgt_protect_table_find(info, gfn);
|
|
|
|
|
if (p) {
|
|
|
|
|
hash_del(&p->hnode);
|
|
|
|
|
kfree(p);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-20 15:31:16 +08:00
|
|
|
static size_t intel_vgpu_reg_rw_opregion(struct intel_vgpu *vgpu, char *buf,
|
|
|
|
|
size_t count, loff_t *ppos, bool iswrite)
|
|
|
|
|
{
|
|
|
|
|
unsigned int i = VFIO_PCI_OFFSET_TO_INDEX(*ppos) -
|
|
|
|
|
VFIO_PCI_NUM_REGIONS;
|
2022-04-11 16:13:39 +02:00
|
|
|
void *base = vgpu->region[i].data;
|
2017-11-20 15:31:16 +08:00
|
|
|
loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
|
|
|
|
|
|
2020-02-17 17:38:58 +01:00
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
if (pos >= vgpu->region[i].size || iswrite) {
|
2017-11-20 15:31:16 +08:00
|
|
|
gvt_vgpu_err("invalid op or offset for Intel vgpu OpRegion\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
2022-04-11 16:13:39 +02:00
|
|
|
count = min(count, (size_t)(vgpu->region[i].size - pos));
|
2017-11-20 15:31:16 +08:00
|
|
|
memcpy(buf, base + pos, count);
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_vgpu_reg_release_opregion(struct intel_vgpu *vgpu,
|
|
|
|
|
struct vfio_region *region)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct intel_vgpu_regops intel_vgpu_regops_opregion = {
|
|
|
|
|
.rw = intel_vgpu_reg_rw_opregion,
|
|
|
|
|
.release = intel_vgpu_reg_release_opregion,
|
|
|
|
|
};
|
|
|
|
|
|
2019-01-30 18:25:54 +08:00
|
|
|
static int handle_edid_regs(struct intel_vgpu *vgpu,
|
|
|
|
|
struct vfio_edid_region *region, char *buf,
|
|
|
|
|
size_t count, u16 offset, bool is_write)
|
|
|
|
|
{
|
|
|
|
|
struct vfio_region_gfx_edid *regs = ®ion->vfio_edid_regs;
|
|
|
|
|
unsigned int data;
|
|
|
|
|
|
|
|
|
|
if (offset + count > sizeof(*regs))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (count != 4)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (is_write) {
|
|
|
|
|
data = *((unsigned int *)buf);
|
|
|
|
|
switch (offset) {
|
|
|
|
|
case offsetof(struct vfio_region_gfx_edid, link_state):
|
|
|
|
|
if (data == VFIO_DEVICE_GFX_LINK_STATE_UP) {
|
|
|
|
|
if (!drm_edid_block_valid(
|
|
|
|
|
(u8 *)region->edid_blob,
|
|
|
|
|
0,
|
|
|
|
|
true,
|
|
|
|
|
NULL)) {
|
|
|
|
|
gvt_vgpu_err("invalid EDID blob\n");
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
2022-04-11 16:13:36 +02:00
|
|
|
intel_vgpu_emulate_hotplug(vgpu, true);
|
2019-01-30 18:25:54 +08:00
|
|
|
} else if (data == VFIO_DEVICE_GFX_LINK_STATE_DOWN)
|
2022-04-11 16:13:36 +02:00
|
|
|
intel_vgpu_emulate_hotplug(vgpu, false);
|
2019-01-30 18:25:54 +08:00
|
|
|
else {
|
|
|
|
|
gvt_vgpu_err("invalid EDID link state %d\n",
|
|
|
|
|
regs->link_state);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
regs->link_state = data;
|
|
|
|
|
break;
|
|
|
|
|
case offsetof(struct vfio_region_gfx_edid, edid_size):
|
|
|
|
|
if (data > regs->edid_max_size) {
|
|
|
|
|
gvt_vgpu_err("EDID size is bigger than %d!\n",
|
|
|
|
|
regs->edid_max_size);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
regs->edid_size = data;
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
/* read-only regs */
|
|
|
|
|
gvt_vgpu_err("write read-only EDID region at offset %d\n",
|
|
|
|
|
offset);
|
|
|
|
|
return -EPERM;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
memcpy(buf, (char *)regs + offset, count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int handle_edid_blob(struct vfio_edid_region *region, char *buf,
|
|
|
|
|
size_t count, u16 offset, bool is_write)
|
|
|
|
|
{
|
|
|
|
|
if (offset + count > region->vfio_edid_regs.edid_size)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (is_write)
|
|
|
|
|
memcpy(region->edid_blob + offset, buf, count);
|
|
|
|
|
else
|
|
|
|
|
memcpy(buf, region->edid_blob + 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;
|
2022-04-11 16:13:39 +02:00
|
|
|
struct vfio_edid_region *region = vgpu->region[i].data;
|
2019-01-30 18:25:54 +08:00
|
|
|
loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
|
|
|
|
|
|
|
|
|
|
if (pos < region->vfio_edid_regs.edid_offset) {
|
|
|
|
|
ret = handle_edid_regs(vgpu, region, buf, count, pos, iswrite);
|
|
|
|
|
} else {
|
|
|
|
|
pos -= EDID_BLOB_OFFSET;
|
|
|
|
|
ret = handle_edid_blob(region, buf, count, pos, iswrite);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
|
gvt_vgpu_err("failed to access EDID region\n");
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_vgpu_reg_release_edid(struct intel_vgpu *vgpu,
|
|
|
|
|
struct vfio_region *region)
|
|
|
|
|
{
|
|
|
|
|
kfree(region->data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct intel_vgpu_regops intel_vgpu_regops_edid = {
|
|
|
|
|
.rw = intel_vgpu_reg_rw_edid,
|
|
|
|
|
.release = intel_vgpu_reg_release_edid,
|
|
|
|
|
};
|
|
|
|
|
|
2017-11-20 15:31:16 +08:00
|
|
|
static int intel_vgpu_register_reg(struct intel_vgpu *vgpu,
|
|
|
|
|
unsigned int type, unsigned int subtype,
|
|
|
|
|
const struct intel_vgpu_regops *ops,
|
|
|
|
|
size_t size, u32 flags, void *data)
|
|
|
|
|
{
|
|
|
|
|
struct vfio_region *region;
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
region = krealloc(vgpu->region,
|
|
|
|
|
(vgpu->num_regions + 1) * sizeof(*region),
|
2017-11-20 15:31:16 +08:00
|
|
|
GFP_KERNEL);
|
|
|
|
|
if (!region)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->region = region;
|
|
|
|
|
vgpu->region[vgpu->num_regions].type = type;
|
|
|
|
|
vgpu->region[vgpu->num_regions].subtype = subtype;
|
|
|
|
|
vgpu->region[vgpu->num_regions].ops = ops;
|
|
|
|
|
vgpu->region[vgpu->num_regions].size = size;
|
|
|
|
|
vgpu->region[vgpu->num_regions].flags = flags;
|
|
|
|
|
vgpu->region[vgpu->num_regions].data = data;
|
|
|
|
|
vgpu->num_regions++;
|
2017-11-23 16:26:36 +08:00
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:44 +02:00
|
|
|
int intel_gvt_set_opregion(struct intel_vgpu *vgpu)
|
2017-11-20 15:31:16 +08:00
|
|
|
{
|
|
|
|
|
void *base;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
/* Each vgpu has its own opregion, although VFIO would create another
|
|
|
|
|
* one later. This one is used to expose opregion to VFIO. And the
|
|
|
|
|
* other one created by VFIO later, is used by guest actually.
|
|
|
|
|
*/
|
|
|
|
|
base = vgpu_opregion(vgpu)->va;
|
|
|
|
|
if (!base)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
if (memcmp(base, OPREGION_SIGNATURE, 16)) {
|
|
|
|
|
memunmap(base);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = intel_vgpu_register_reg(vgpu,
|
|
|
|
|
PCI_VENDOR_ID_INTEL | VFIO_REGION_TYPE_PCI_VENDOR_TYPE,
|
|
|
|
|
VFIO_REGION_SUBTYPE_INTEL_IGD_OPREGION,
|
|
|
|
|
&intel_vgpu_regops_opregion, OPREGION_SIZE,
|
|
|
|
|
VFIO_REGION_INFO_FLAG_READ, base);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:44 +02:00
|
|
|
int intel_gvt_set_edid(struct intel_vgpu *vgpu, int port_num)
|
2019-01-30 18:25:54 +08:00
|
|
|
{
|
|
|
|
|
struct intel_vgpu_port *port = intel_vgpu_port(vgpu, port_num);
|
|
|
|
|
struct vfio_edid_region *base;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
base = kzalloc(sizeof(*base), GFP_KERNEL);
|
|
|
|
|
if (!base)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
/* TODO: Add multi-port and EDID extension block support */
|
|
|
|
|
base->vfio_edid_regs.edid_offset = EDID_BLOB_OFFSET;
|
|
|
|
|
base->vfio_edid_regs.edid_max_size = EDID_SIZE;
|
|
|
|
|
base->vfio_edid_regs.edid_size = EDID_SIZE;
|
|
|
|
|
base->vfio_edid_regs.max_xres = vgpu_edid_xres(port->id);
|
|
|
|
|
base->vfio_edid_regs.max_yres = vgpu_edid_yres(port->id);
|
|
|
|
|
base->edid_blob = port->edid->edid_block;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
static int intel_vgpu_iommu_notifier(struct notifier_block *nb,
|
|
|
|
|
unsigned long action, void *data)
|
|
|
|
|
{
|
2022-04-11 16:13:39 +02:00
|
|
|
struct intel_vgpu *vgpu =
|
|
|
|
|
container_of(nb, struct intel_vgpu, iommu_notifier);
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
|
if (action == VFIO_IOMMU_NOTIFY_DMA_UNMAP) {
|
|
|
|
|
struct vfio_iommu_type1_dma_unmap *unmap = data;
|
2018-03-01 15:49:59 +08:00
|
|
|
struct gvt_dma *entry;
|
|
|
|
|
unsigned long iov_pfn, end_iov_pfn;
|
|
|
|
|
|
|
|
|
|
iov_pfn = unmap->iova >> PAGE_SHIFT;
|
|
|
|
|
end_iov_pfn = iov_pfn + unmap->size / PAGE_SIZE;
|
2016-12-08 11:00:36 +08:00
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_lock(&vgpu->cache_lock);
|
2018-03-01 15:49:59 +08:00
|
|
|
for (; iov_pfn < end_iov_pfn; iov_pfn++) {
|
|
|
|
|
entry = __gvt_cache_find_gfn(vgpu, iov_pfn);
|
|
|
|
|
if (!entry)
|
|
|
|
|
continue;
|
2016-12-08 11:00:36 +08:00
|
|
|
|
2018-05-15 10:35:42 +08:00
|
|
|
gvt_dma_unmap_page(vgpu, entry->gfn, entry->dma_addr,
|
|
|
|
|
entry->size);
|
2018-03-01 15:49:59 +08:00
|
|
|
__gvt_cache_remove_entry(vgpu, entry);
|
|
|
|
|
}
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_unlock(&vgpu->cache_lock);
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NOTIFY_OK;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:56 +02:00
|
|
|
static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu)
|
|
|
|
|
{
|
|
|
|
|
struct intel_vgpu *itr;
|
|
|
|
|
int id;
|
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&vgpu->gvt->lock);
|
|
|
|
|
for_each_active_vgpu(vgpu->gvt, itr, id) {
|
|
|
|
|
if (!itr->attached)
|
|
|
|
|
continue;
|
|
|
|
|
|
2022-05-19 14:33:11 -04:00
|
|
|
if (vgpu->vfio_device.kvm == itr->vfio_device.kvm) {
|
2022-04-11 16:13:56 +02:00
|
|
|
ret = true;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
out:
|
|
|
|
|
mutex_unlock(&vgpu->gvt->lock);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
static int intel_vgpu_open_device(struct vfio_device *vfio_dev)
|
2016-12-08 11:00:36 +08:00
|
|
|
{
|
2022-04-11 16:13:57 +02:00
|
|
|
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
|
2016-12-08 11:00:36 +08:00
|
|
|
unsigned long events;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->iommu_notifier.notifier_call = intel_vgpu_iommu_notifier;
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
|
events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
|
2022-05-11 13:12:58 -06:00
|
|
|
ret = vfio_register_notifier(vfio_dev, VFIO_IOMMU_NOTIFY, &events,
|
|
|
|
|
&vgpu->iommu_notifier);
|
2016-12-08 11:00:36 +08:00
|
|
|
if (ret != 0) {
|
2017-03-10 04:26:53 -05:00
|
|
|
gvt_vgpu_err("vfio_register_notifier for iommu failed: %d\n",
|
|
|
|
|
ret);
|
2016-12-08 11:00:36 +08:00
|
|
|
goto out;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:56 +02:00
|
|
|
ret = -EEXIST;
|
|
|
|
|
if (vgpu->attached)
|
2022-05-19 14:33:11 -04:00
|
|
|
goto undo_iommu;
|
2022-04-11 16:13:56 +02:00
|
|
|
|
|
|
|
|
ret = -ESRCH;
|
2022-05-19 14:33:11 -04:00
|
|
|
if (!vgpu->vfio_device.kvm ||
|
|
|
|
|
vgpu->vfio_device.kvm->mm != current->mm) {
|
2022-04-11 16:13:56 +02:00
|
|
|
gvt_vgpu_err("KVM is required to use Intel vGPU\n");
|
2022-05-19 14:33:11 -04:00
|
|
|
goto undo_iommu;
|
2022-04-11 16:13:56 +02:00
|
|
|
}
|
|
|
|
|
|
2022-05-19 14:33:11 -04:00
|
|
|
kvm_get_kvm(vgpu->vfio_device.kvm);
|
|
|
|
|
|
2022-04-11 16:13:56 +02:00
|
|
|
ret = -EEXIST;
|
|
|
|
|
if (__kvmgt_vgpu_exist(vgpu))
|
2022-05-19 14:33:11 -04:00
|
|
|
goto undo_iommu;
|
2016-12-16 10:51:06 +08:00
|
|
|
|
2022-04-11 16:13:56 +02:00
|
|
|
vgpu->attached = true;
|
|
|
|
|
|
|
|
|
|
kvmgt_protect_table_init(vgpu);
|
|
|
|
|
gvt_cache_init(vgpu);
|
|
|
|
|
|
|
|
|
|
vgpu->track_node.track_write = kvmgt_page_track_write;
|
|
|
|
|
vgpu->track_node.track_flush_slot = kvmgt_page_track_flush_slot;
|
2022-05-19 14:33:11 -04:00
|
|
|
kvm_page_track_register_notifier(vgpu->vfio_device.kvm,
|
|
|
|
|
&vgpu->track_node);
|
2022-04-11 16:13:56 +02:00
|
|
|
|
|
|
|
|
debugfs_create_ulong(KVMGT_DEBUGFS_FILENAME, 0444, vgpu->debugfs,
|
|
|
|
|
&vgpu->nr_cache_entries);
|
|
|
|
|
|
2022-04-11 16:13:36 +02:00
|
|
|
intel_gvt_activate_vgpu(vgpu);
|
2017-03-30 01:48:39 +08:00
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
atomic_set(&vgpu->released, 0);
|
2022-04-11 16:13:56 +02:00
|
|
|
return 0;
|
2016-12-16 10:51:06 +08:00
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
undo_iommu:
|
2022-05-11 13:12:58 -06:00
|
|
|
vfio_unregister_notifier(vfio_dev, VFIO_IOMMU_NOTIFY,
|
|
|
|
|
&vgpu->iommu_notifier);
|
2016-12-08 11:00:36 +08:00
|
|
|
out:
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-13 10:26:16 +08:00
|
|
|
static void intel_vgpu_release_msi_eventfd_ctx(struct intel_vgpu *vgpu)
|
|
|
|
|
{
|
|
|
|
|
struct eventfd_ctx *trigger;
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
trigger = vgpu->msi_trigger;
|
2018-04-13 10:26:16 +08:00
|
|
|
if (trigger) {
|
|
|
|
|
eventfd_ctx_put(trigger);
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->msi_trigger = NULL;
|
2018-04-13 10:26:16 +08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-19 14:33:11 -04:00
|
|
|
static void intel_vgpu_close_device(struct vfio_device *vfio_dev)
|
2016-12-08 11:00:36 +08:00
|
|
|
{
|
2022-05-19 14:33:11 -04:00
|
|
|
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
|
2020-03-06 10:08:10 +08:00
|
|
|
struct drm_i915_private *i915 = vgpu->gvt->gt->i915;
|
2016-12-16 10:51:06 +08:00
|
|
|
int ret;
|
2016-12-08 11:00:36 +08:00
|
|
|
|
2022-04-11 16:13:41 +02:00
|
|
|
if (!vgpu->attached)
|
2016-12-08 11:00:36 +08:00
|
|
|
return;
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
if (atomic_cmpxchg(&vgpu->released, 0, 1))
|
2016-12-16 10:51:06 +08:00
|
|
|
return;
|
|
|
|
|
|
2022-04-11 16:13:36 +02:00
|
|
|
intel_gvt_release_vgpu(vgpu);
|
2017-03-30 01:48:39 +08:00
|
|
|
|
2022-05-11 13:12:58 -06:00
|
|
|
ret = vfio_unregister_notifier(&vgpu->vfio_device, VFIO_IOMMU_NOTIFY,
|
|
|
|
|
&vgpu->iommu_notifier);
|
2020-02-20 22:25:07 +05:30
|
|
|
drm_WARN(&i915->drm, ret,
|
|
|
|
|
"vfio_unregister_notifier for iommu failed: %d\n", ret);
|
2016-12-16 10:51:06 +08:00
|
|
|
|
2022-04-11 16:13:56 +02:00
|
|
|
debugfs_remove(debugfs_lookup(KVMGT_DEBUGFS_FILENAME, vgpu->debugfs));
|
|
|
|
|
|
2022-05-19 14:33:11 -04:00
|
|
|
kvm_page_track_unregister_notifier(vgpu->vfio_device.kvm,
|
|
|
|
|
&vgpu->track_node);
|
2022-04-11 16:13:56 +02:00
|
|
|
kvmgt_protect_table_destroy(vgpu);
|
|
|
|
|
gvt_cache_destroy(vgpu);
|
2016-12-16 10:51:06 +08:00
|
|
|
|
2018-04-13 10:26:16 +08:00
|
|
|
intel_vgpu_release_msi_eventfd_ctx(vgpu);
|
|
|
|
|
|
2022-04-11 16:13:41 +02:00
|
|
|
vgpu->attached = false;
|
2016-12-16 10:51:07 +08:00
|
|
|
|
2022-05-19 14:33:11 -04:00
|
|
|
if (vgpu->vfio_device.kvm)
|
|
|
|
|
kvm_put_kvm(vgpu->vfio_device.kvm);
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
2019-01-21 11:51:41 +02:00
|
|
|
static u64 intel_vgpu_get_bar_addr(struct intel_vgpu *vgpu, int bar)
|
2016-12-08 11:00:36 +08:00
|
|
|
{
|
|
|
|
|
u32 start_lo, start_hi;
|
|
|
|
|
u32 mem_type;
|
|
|
|
|
|
2017-08-15 13:14:04 +08:00
|
|
|
start_lo = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + bar)) &
|
2016-12-08 11:00:36 +08:00
|
|
|
PCI_BASE_ADDRESS_MEM_MASK;
|
2017-08-15 13:14:04 +08:00
|
|
|
mem_type = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space + bar)) &
|
2016-12-08 11:00:36 +08:00
|
|
|
PCI_BASE_ADDRESS_MEM_TYPE_MASK;
|
|
|
|
|
|
|
|
|
|
switch (mem_type) {
|
|
|
|
|
case PCI_BASE_ADDRESS_MEM_TYPE_64:
|
|
|
|
|
start_hi = (*(u32 *)(vgpu->cfg_space.virtual_cfg_space
|
2017-08-15 13:14:04 +08:00
|
|
|
+ bar + 4));
|
2016-12-08 11:00:36 +08:00
|
|
|
break;
|
|
|
|
|
case PCI_BASE_ADDRESS_MEM_TYPE_32:
|
|
|
|
|
case PCI_BASE_ADDRESS_MEM_TYPE_1M:
|
|
|
|
|
/* 1M mem BAR treated as 32-bit BAR */
|
|
|
|
|
default:
|
|
|
|
|
/* mem unknown type treated as 32-bit BAR */
|
|
|
|
|
start_hi = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ((u64)start_hi << 32) | start_lo;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 11:51:41 +02:00
|
|
|
static int intel_vgpu_bar_rw(struct intel_vgpu *vgpu, int bar, u64 off,
|
2017-08-15 13:14:04 +08:00
|
|
|
void *buf, unsigned int count, bool is_write)
|
|
|
|
|
{
|
2019-01-21 11:51:41 +02:00
|
|
|
u64 bar_start = intel_vgpu_get_bar_addr(vgpu, bar);
|
2017-08-15 13:14:04 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (is_write)
|
2022-04-11 16:13:36 +02:00
|
|
|
ret = intel_vgpu_emulate_mmio_write(vgpu,
|
2017-08-15 13:14:04 +08:00
|
|
|
bar_start + off, buf, count);
|
|
|
|
|
else
|
2022-04-11 16:13:36 +02:00
|
|
|
ret = intel_vgpu_emulate_mmio_read(vgpu,
|
2017-08-15 13:14:04 +08:00
|
|
|
bar_start + off, buf, count);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 11:51:41 +02:00
|
|
|
static inline bool intel_vgpu_in_aperture(struct intel_vgpu *vgpu, u64 off)
|
2018-01-30 13:51:31 +08:00
|
|
|
{
|
|
|
|
|
return off >= vgpu_aperture_offset(vgpu) &&
|
|
|
|
|
off < vgpu_aperture_offset(vgpu) + vgpu_aperture_sz(vgpu);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 11:51:41 +02:00
|
|
|
static int intel_vgpu_aperture_rw(struct intel_vgpu *vgpu, u64 off,
|
2018-01-30 13:51:31 +08:00
|
|
|
void *buf, unsigned long count, bool is_write)
|
|
|
|
|
{
|
2019-04-04 08:14:25 +01:00
|
|
|
void __iomem *aperture_va;
|
2018-01-30 13:51:31 +08:00
|
|
|
|
|
|
|
|
if (!intel_vgpu_in_aperture(vgpu, off) ||
|
|
|
|
|
!intel_vgpu_in_aperture(vgpu, off + count)) {
|
|
|
|
|
gvt_vgpu_err("Invalid aperture offset %llu\n", off);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-06 10:08:10 +08:00
|
|
|
aperture_va = io_mapping_map_wc(&vgpu->gvt->gt->ggtt->iomap,
|
2018-01-30 13:51:31 +08:00
|
|
|
ALIGN_DOWN(off, PAGE_SIZE),
|
|
|
|
|
count + offset_in_page(off));
|
|
|
|
|
if (!aperture_va)
|
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
|
|
if (is_write)
|
2019-04-04 08:14:25 +01:00
|
|
|
memcpy_toio(aperture_va + offset_in_page(off), buf, count);
|
2018-01-30 13:51:31 +08:00
|
|
|
else
|
2019-04-04 08:14:25 +01:00
|
|
|
memcpy_fromio(buf, aperture_va + offset_in_page(off), count);
|
2018-01-30 13:51:31 +08:00
|
|
|
|
|
|
|
|
io_mapping_unmap(aperture_va);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
static ssize_t intel_vgpu_rw(struct intel_vgpu *vgpu, char *buf,
|
2016-12-08 11:00:36 +08:00
|
|
|
size_t count, loff_t *ppos, bool is_write)
|
|
|
|
|
{
|
|
|
|
|
unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
|
2019-01-21 11:51:41 +02:00
|
|
|
u64 pos = *ppos & VFIO_PCI_OFFSET_MASK;
|
2016-12-08 11:00:36 +08:00
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
if (index >= VFIO_PCI_NUM_REGIONS + vgpu->num_regions) {
|
2017-03-10 04:26:53 -05:00
|
|
|
gvt_vgpu_err("invalid index: %u\n", index);
|
2016-12-08 11:00:36 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
switch (index) {
|
|
|
|
|
case VFIO_PCI_CONFIG_REGION_INDEX:
|
|
|
|
|
if (is_write)
|
2022-04-11 16:13:36 +02:00
|
|
|
ret = intel_vgpu_emulate_cfg_write(vgpu, pos,
|
2016-12-08 11:00:36 +08:00
|
|
|
buf, count);
|
|
|
|
|
else
|
2022-04-11 16:13:36 +02:00
|
|
|
ret = intel_vgpu_emulate_cfg_read(vgpu, pos,
|
2016-12-08 11:00:36 +08:00
|
|
|
buf, count);
|
|
|
|
|
break;
|
|
|
|
|
case VFIO_PCI_BAR0_REGION_INDEX:
|
2017-08-15 13:14:04 +08:00
|
|
|
ret = intel_vgpu_bar_rw(vgpu, PCI_BASE_ADDRESS_0, pos,
|
|
|
|
|
buf, count, is_write);
|
2016-12-08 11:00:36 +08:00
|
|
|
break;
|
|
|
|
|
case VFIO_PCI_BAR2_REGION_INDEX:
|
2018-01-30 13:51:31 +08:00
|
|
|
ret = intel_vgpu_aperture_rw(vgpu, pos, buf, count, is_write);
|
2017-08-15 13:14:04 +08:00
|
|
|
break;
|
|
|
|
|
case VFIO_PCI_BAR1_REGION_INDEX:
|
2016-12-08 11:00:36 +08:00
|
|
|
case VFIO_PCI_BAR3_REGION_INDEX:
|
|
|
|
|
case VFIO_PCI_BAR4_REGION_INDEX:
|
|
|
|
|
case VFIO_PCI_BAR5_REGION_INDEX:
|
|
|
|
|
case VFIO_PCI_VGA_REGION_INDEX:
|
|
|
|
|
case VFIO_PCI_ROM_REGION_INDEX:
|
2017-11-20 15:31:16 +08:00
|
|
|
break;
|
2016-12-08 11:00:36 +08:00
|
|
|
default:
|
2022-04-11 16:13:39 +02:00
|
|
|
if (index >= VFIO_PCI_NUM_REGIONS + vgpu->num_regions)
|
2017-11-20 15:31:16 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
index -= VFIO_PCI_NUM_REGIONS;
|
2022-04-11 16:13:39 +02:00
|
|
|
return vgpu->region[index].ops->rw(vgpu, buf, count,
|
2017-11-20 15:31:16 +08:00
|
|
|
ppos, is_write);
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret == 0 ? count : ret;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
static bool gtt_entry(struct intel_vgpu *vgpu, loff_t *ppos)
|
2018-02-11 14:59:19 +08:00
|
|
|
{
|
|
|
|
|
unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
|
|
|
|
|
struct intel_gvt *gvt = vgpu->gvt;
|
|
|
|
|
int offset;
|
|
|
|
|
|
|
|
|
|
/* Only allow MMIO GGTT entry access */
|
|
|
|
|
if (index != PCI_BASE_ADDRESS_0)
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
offset = (u64)(*ppos & VFIO_PCI_OFFSET_MASK) -
|
|
|
|
|
intel_vgpu_get_bar_gpa(vgpu, PCI_BASE_ADDRESS_0);
|
|
|
|
|
|
|
|
|
|
return (offset >= gvt->device_info.gtt_start_offset &&
|
|
|
|
|
offset < gvt->device_info.gtt_start_offset + gvt_ggtt_sz(gvt)) ?
|
|
|
|
|
true : false;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
static ssize_t intel_vgpu_read(struct vfio_device *vfio_dev, char __user *buf,
|
2016-12-08 11:00:36 +08:00
|
|
|
size_t count, loff_t *ppos)
|
|
|
|
|
{
|
2022-04-11 16:13:57 +02:00
|
|
|
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
|
2016-12-08 11:00:36 +08:00
|
|
|
unsigned int done = 0;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
|
size_t filled;
|
|
|
|
|
|
2018-02-11 14:59:19 +08:00
|
|
|
/* Only support GGTT entry 8 bytes read */
|
|
|
|
|
if (count >= 8 && !(*ppos % 8) &&
|
2022-04-11 16:13:55 +02:00
|
|
|
gtt_entry(vgpu, ppos)) {
|
2018-02-11 14:59:19 +08:00
|
|
|
u64 val;
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
ret = intel_vgpu_rw(vgpu, (char *)&val, sizeof(val),
|
2018-02-11 14:59:19 +08:00
|
|
|
ppos, false);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
|
|
if (copy_to_user(buf, &val, sizeof(val)))
|
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
|
|
filled = 8;
|
|
|
|
|
} else if (count >= 4 && !(*ppos % 4)) {
|
2016-12-08 11:00:36 +08:00
|
|
|
u32 val;
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
ret = intel_vgpu_rw(vgpu, (char *)&val, sizeof(val),
|
2016-12-08 11:00:36 +08:00
|
|
|
ppos, false);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
|
|
if (copy_to_user(buf, &val, sizeof(val)))
|
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
|
|
filled = 4;
|
|
|
|
|
} else if (count >= 2 && !(*ppos % 2)) {
|
|
|
|
|
u16 val;
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
ret = intel_vgpu_rw(vgpu, (char *)&val, sizeof(val),
|
2016-12-08 11:00:36 +08:00
|
|
|
ppos, false);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
|
|
if (copy_to_user(buf, &val, sizeof(val)))
|
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
|
|
filled = 2;
|
|
|
|
|
} else {
|
|
|
|
|
u8 val;
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
ret = intel_vgpu_rw(vgpu, &val, sizeof(val), ppos,
|
2016-12-08 11:00:36 +08:00
|
|
|
false);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
|
|
if (copy_to_user(buf, &val, sizeof(val)))
|
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
|
|
filled = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count -= filled;
|
|
|
|
|
done += filled;
|
|
|
|
|
*ppos += filled;
|
|
|
|
|
buf += filled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return done;
|
|
|
|
|
|
|
|
|
|
read_err:
|
|
|
|
|
return -EFAULT;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
static ssize_t intel_vgpu_write(struct vfio_device *vfio_dev,
|
2016-12-08 11:00:36 +08:00
|
|
|
const char __user *buf,
|
|
|
|
|
size_t count, loff_t *ppos)
|
|
|
|
|
{
|
2022-04-11 16:13:57 +02:00
|
|
|
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
|
2016-12-08 11:00:36 +08:00
|
|
|
unsigned int done = 0;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
|
size_t filled;
|
|
|
|
|
|
2018-02-11 14:59:19 +08:00
|
|
|
/* Only support GGTT entry 8 bytes write */
|
|
|
|
|
if (count >= 8 && !(*ppos % 8) &&
|
2022-04-11 16:13:55 +02:00
|
|
|
gtt_entry(vgpu, ppos)) {
|
2018-02-11 14:59:19 +08:00
|
|
|
u64 val;
|
|
|
|
|
|
|
|
|
|
if (copy_from_user(&val, buf, sizeof(val)))
|
|
|
|
|
goto write_err;
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
ret = intel_vgpu_rw(vgpu, (char *)&val, sizeof(val),
|
2018-02-11 14:59:19 +08:00
|
|
|
ppos, true);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
goto write_err;
|
|
|
|
|
|
|
|
|
|
filled = 8;
|
|
|
|
|
} else if (count >= 4 && !(*ppos % 4)) {
|
2016-12-08 11:00:36 +08:00
|
|
|
u32 val;
|
|
|
|
|
|
|
|
|
|
if (copy_from_user(&val, buf, sizeof(val)))
|
|
|
|
|
goto write_err;
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
ret = intel_vgpu_rw(vgpu, (char *)&val, sizeof(val),
|
2016-12-08 11:00:36 +08:00
|
|
|
ppos, true);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
goto write_err;
|
|
|
|
|
|
|
|
|
|
filled = 4;
|
|
|
|
|
} else if (count >= 2 && !(*ppos % 2)) {
|
|
|
|
|
u16 val;
|
|
|
|
|
|
|
|
|
|
if (copy_from_user(&val, buf, sizeof(val)))
|
|
|
|
|
goto write_err;
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
ret = intel_vgpu_rw(vgpu, (char *)&val,
|
2016-12-08 11:00:36 +08:00
|
|
|
sizeof(val), ppos, true);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
goto write_err;
|
|
|
|
|
|
|
|
|
|
filled = 2;
|
|
|
|
|
} else {
|
|
|
|
|
u8 val;
|
|
|
|
|
|
|
|
|
|
if (copy_from_user(&val, buf, sizeof(val)))
|
|
|
|
|
goto write_err;
|
|
|
|
|
|
2022-04-11 16:13:55 +02:00
|
|
|
ret = intel_vgpu_rw(vgpu, &val, sizeof(val),
|
2016-12-08 11:00:36 +08:00
|
|
|
ppos, true);
|
|
|
|
|
if (ret <= 0)
|
|
|
|
|
goto write_err;
|
|
|
|
|
|
|
|
|
|
filled = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
count -= filled;
|
|
|
|
|
done += filled;
|
|
|
|
|
*ppos += filled;
|
|
|
|
|
buf += filled;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return done;
|
|
|
|
|
write_err:
|
|
|
|
|
return -EFAULT;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
static int intel_vgpu_mmap(struct vfio_device *vfio_dev,
|
|
|
|
|
struct vm_area_struct *vma)
|
2016-12-08 11:00:36 +08:00
|
|
|
{
|
2022-04-11 16:13:57 +02:00
|
|
|
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
|
2016-12-08 11:00:36 +08:00
|
|
|
unsigned int index;
|
|
|
|
|
u64 virtaddr;
|
2019-01-11 13:58:53 +08:00
|
|
|
unsigned long req_size, pgoff, req_start;
|
2016-12-08 11:00:36 +08:00
|
|
|
pgprot_t pg_prot;
|
|
|
|
|
|
|
|
|
|
index = vma->vm_pgoff >> (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT);
|
|
|
|
|
if (index >= VFIO_PCI_ROM_REGION_INDEX)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
if (vma->vm_end < vma->vm_start)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
if ((vma->vm_flags & VM_SHARED) == 0)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
if (index != VFIO_PCI_BAR2_REGION_INDEX)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
pg_prot = vma->vm_page_prot;
|
|
|
|
|
virtaddr = vma->vm_start;
|
|
|
|
|
req_size = vma->vm_end - vma->vm_start;
|
2019-01-11 13:58:53 +08:00
|
|
|
pgoff = vma->vm_pgoff &
|
|
|
|
|
((1U << (VFIO_PCI_OFFSET_SHIFT - PAGE_SHIFT)) - 1);
|
|
|
|
|
req_start = pgoff << PAGE_SHIFT;
|
|
|
|
|
|
|
|
|
|
if (!intel_vgpu_in_aperture(vgpu, req_start))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
if (req_start + req_size >
|
|
|
|
|
vgpu_aperture_offset(vgpu) + vgpu_aperture_sz(vgpu))
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
pgoff = (gvt_aperture_pa_base(vgpu->gvt) >> PAGE_SHIFT) + pgoff;
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
|
return remap_pfn_range(vma, virtaddr, pgoff, req_size, pg_prot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_vgpu_get_irq_count(struct intel_vgpu *vgpu, int type)
|
|
|
|
|
{
|
|
|
|
|
if (type == VFIO_PCI_INTX_IRQ_INDEX || type == VFIO_PCI_MSI_IRQ_INDEX)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_vgpu_set_intx_mask(struct intel_vgpu *vgpu,
|
|
|
|
|
unsigned int index, unsigned int start,
|
2019-01-21 11:51:41 +02:00
|
|
|
unsigned int count, u32 flags,
|
2016-12-08 11:00:36 +08:00
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_vgpu_set_intx_unmask(struct intel_vgpu *vgpu,
|
|
|
|
|
unsigned int index, unsigned int start,
|
2019-01-21 11:51:41 +02:00
|
|
|
unsigned int count, u32 flags, void *data)
|
2016-12-08 11:00:36 +08:00
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_vgpu_set_intx_trigger(struct intel_vgpu *vgpu,
|
|
|
|
|
unsigned int index, unsigned int start, unsigned int count,
|
2019-01-21 11:51:41 +02:00
|
|
|
u32 flags, void *data)
|
2016-12-08 11:00:36 +08:00
|
|
|
{
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int intel_vgpu_set_msi_trigger(struct intel_vgpu *vgpu,
|
|
|
|
|
unsigned int index, unsigned int start, unsigned int count,
|
2019-01-21 11:51:41 +02:00
|
|
|
u32 flags, void *data)
|
2016-12-08 11:00:36 +08:00
|
|
|
{
|
|
|
|
|
struct eventfd_ctx *trigger;
|
|
|
|
|
|
|
|
|
|
if (flags & VFIO_IRQ_SET_DATA_EVENTFD) {
|
|
|
|
|
int fd = *(int *)data;
|
|
|
|
|
|
|
|
|
|
trigger = eventfd_ctx_fdget(fd);
|
|
|
|
|
if (IS_ERR(trigger)) {
|
2017-03-10 04:26:53 -05:00
|
|
|
gvt_vgpu_err("eventfd_ctx_fdget failed\n");
|
2016-12-08 11:00:36 +08:00
|
|
|
return PTR_ERR(trigger);
|
|
|
|
|
}
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->msi_trigger = trigger;
|
2018-04-13 10:26:16 +08:00
|
|
|
} else if ((flags & VFIO_IRQ_SET_DATA_NONE) && !count)
|
|
|
|
|
intel_vgpu_release_msi_eventfd_ctx(vgpu);
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-21 11:51:41 +02:00
|
|
|
static int intel_vgpu_set_irqs(struct intel_vgpu *vgpu, u32 flags,
|
2016-12-08 11:00:36 +08:00
|
|
|
unsigned int index, unsigned int start, unsigned int count,
|
|
|
|
|
void *data)
|
|
|
|
|
{
|
|
|
|
|
int (*func)(struct intel_vgpu *vgpu, unsigned int index,
|
2019-01-21 11:51:41 +02:00
|
|
|
unsigned int start, unsigned int count, u32 flags,
|
2016-12-08 11:00:36 +08:00
|
|
|
void *data) = NULL;
|
|
|
|
|
|
|
|
|
|
switch (index) {
|
|
|
|
|
case VFIO_PCI_INTX_IRQ_INDEX:
|
|
|
|
|
switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
|
|
|
|
|
case VFIO_IRQ_SET_ACTION_MASK:
|
|
|
|
|
func = intel_vgpu_set_intx_mask;
|
|
|
|
|
break;
|
|
|
|
|
case VFIO_IRQ_SET_ACTION_UNMASK:
|
|
|
|
|
func = intel_vgpu_set_intx_unmask;
|
|
|
|
|
break;
|
|
|
|
|
case VFIO_IRQ_SET_ACTION_TRIGGER:
|
|
|
|
|
func = intel_vgpu_set_intx_trigger;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
case VFIO_PCI_MSI_IRQ_INDEX:
|
|
|
|
|
switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
|
|
|
|
|
case VFIO_IRQ_SET_ACTION_MASK:
|
|
|
|
|
case VFIO_IRQ_SET_ACTION_UNMASK:
|
|
|
|
|
/* XXX Need masking support exported */
|
|
|
|
|
break;
|
|
|
|
|
case VFIO_IRQ_SET_ACTION_TRIGGER:
|
|
|
|
|
func = intel_vgpu_set_msi_trigger;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!func)
|
|
|
|
|
return -ENOTTY;
|
|
|
|
|
|
|
|
|
|
return func(vgpu, index, start, count, flags, data);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
static long intel_vgpu_ioctl(struct vfio_device *vfio_dev, unsigned int cmd,
|
2016-12-08 11:00:36 +08:00
|
|
|
unsigned long arg)
|
|
|
|
|
{
|
2022-04-11 16:13:57 +02:00
|
|
|
struct intel_vgpu *vgpu = vfio_dev_to_vgpu(vfio_dev);
|
2016-12-08 11:00:36 +08:00
|
|
|
unsigned long minsz;
|
|
|
|
|
|
|
|
|
|
gvt_dbg_core("vgpu%d ioctl, cmd: %d\n", vgpu->id, cmd);
|
|
|
|
|
|
|
|
|
|
if (cmd == VFIO_DEVICE_GET_INFO) {
|
|
|
|
|
struct vfio_device_info info;
|
|
|
|
|
|
|
|
|
|
minsz = offsetofend(struct vfio_device_info, num_irqs);
|
|
|
|
|
|
|
|
|
|
if (copy_from_user(&info, (void __user *)arg, minsz))
|
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
|
|
if (info.argsz < minsz)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
info.flags = VFIO_DEVICE_FLAGS_PCI;
|
|
|
|
|
info.flags |= VFIO_DEVICE_FLAGS_RESET;
|
2017-11-20 15:31:16 +08:00
|
|
|
info.num_regions = VFIO_PCI_NUM_REGIONS +
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->num_regions;
|
2016-12-08 11:00:36 +08:00
|
|
|
info.num_irqs = VFIO_PCI_NUM_IRQS;
|
|
|
|
|
|
|
|
|
|
return copy_to_user((void __user *)arg, &info, minsz) ?
|
|
|
|
|
-EFAULT : 0;
|
|
|
|
|
|
|
|
|
|
} else if (cmd == VFIO_DEVICE_GET_REGION_INFO) {
|
|
|
|
|
struct vfio_region_info info;
|
|
|
|
|
struct vfio_info_cap caps = { .buf = NULL, .size = 0 };
|
2018-08-02 22:40:19 -05:00
|
|
|
unsigned int i;
|
|
|
|
|
int ret;
|
2016-12-08 11:00:36 +08:00
|
|
|
struct vfio_region_info_cap_sparse_mmap *sparse = NULL;
|
|
|
|
|
int nr_areas = 1;
|
|
|
|
|
int cap_type_id;
|
|
|
|
|
|
|
|
|
|
minsz = offsetofend(struct vfio_region_info, offset);
|
|
|
|
|
|
|
|
|
|
if (copy_from_user(&info, (void __user *)arg, minsz))
|
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
|
|
if (info.argsz < minsz)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
switch (info.index) {
|
|
|
|
|
case VFIO_PCI_CONFIG_REGION_INDEX:
|
|
|
|
|
info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
|
2017-08-23 14:08:10 +08:00
|
|
|
info.size = vgpu->gvt->device_info.cfg_space_size;
|
2016-12-08 11:00:36 +08:00
|
|
|
info.flags = VFIO_REGION_INFO_FLAG_READ |
|
|
|
|
|
VFIO_REGION_INFO_FLAG_WRITE;
|
|
|
|
|
break;
|
|
|
|
|
case VFIO_PCI_BAR0_REGION_INDEX:
|
|
|
|
|
info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
|
|
|
|
|
info.size = vgpu->cfg_space.bar[info.index].size;
|
|
|
|
|
if (!info.size) {
|
|
|
|
|
info.flags = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info.flags = VFIO_REGION_INFO_FLAG_READ |
|
|
|
|
|
VFIO_REGION_INFO_FLAG_WRITE;
|
|
|
|
|
break;
|
|
|
|
|
case VFIO_PCI_BAR1_REGION_INDEX:
|
|
|
|
|
info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
|
|
|
|
|
info.size = 0;
|
|
|
|
|
info.flags = 0;
|
|
|
|
|
break;
|
|
|
|
|
case VFIO_PCI_BAR2_REGION_INDEX:
|
|
|
|
|
info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
|
|
|
|
|
info.flags = VFIO_REGION_INFO_FLAG_CAPS |
|
|
|
|
|
VFIO_REGION_INFO_FLAG_MMAP |
|
|
|
|
|
VFIO_REGION_INFO_FLAG_READ |
|
|
|
|
|
VFIO_REGION_INFO_FLAG_WRITE;
|
|
|
|
|
info.size = gvt_aperture_sz(vgpu->gvt);
|
|
|
|
|
|
2019-05-24 12:14:21 -05:00
|
|
|
sparse = kzalloc(struct_size(sparse, areas, nr_areas),
|
|
|
|
|
GFP_KERNEL);
|
2016-12-08 11:00:36 +08:00
|
|
|
if (!sparse)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
2017-12-12 12:59:39 -07:00
|
|
|
sparse->header.id = VFIO_REGION_INFO_CAP_SPARSE_MMAP;
|
|
|
|
|
sparse->header.version = 1;
|
2016-12-08 11:00:36 +08:00
|
|
|
sparse->nr_areas = nr_areas;
|
|
|
|
|
cap_type_id = VFIO_REGION_INFO_CAP_SPARSE_MMAP;
|
|
|
|
|
sparse->areas[0].offset =
|
|
|
|
|
PAGE_ALIGN(vgpu_aperture_offset(vgpu));
|
|
|
|
|
sparse->areas[0].size = vgpu_aperture_sz(vgpu);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VFIO_PCI_BAR3_REGION_INDEX ... VFIO_PCI_BAR5_REGION_INDEX:
|
|
|
|
|
info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
|
|
|
|
|
info.size = 0;
|
|
|
|
|
info.flags = 0;
|
2017-12-08 15:31:12 +08:00
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
gvt_dbg_core("get region info bar:%d\n", info.index);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case VFIO_PCI_ROM_REGION_INDEX:
|
|
|
|
|
case VFIO_PCI_VGA_REGION_INDEX:
|
2017-12-08 15:31:12 +08:00
|
|
|
info.offset = VFIO_PCI_INDEX_TO_OFFSET(info.index);
|
|
|
|
|
info.size = 0;
|
|
|
|
|
info.flags = 0;
|
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
gvt_dbg_core("get region info index:%d\n", info.index);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
{
|
2017-12-12 12:59:39 -07:00
|
|
|
struct vfio_region_info_cap_type cap_type = {
|
|
|
|
|
.header.id = VFIO_REGION_INFO_CAP_TYPE,
|
|
|
|
|
.header.version = 1 };
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
|
if (info.index >= VFIO_PCI_NUM_REGIONS +
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->num_regions)
|
2016-12-08 11:00:36 +08:00
|
|
|
return -EINVAL;
|
2018-08-02 22:40:19 -05:00
|
|
|
info.index =
|
|
|
|
|
array_index_nospec(info.index,
|
|
|
|
|
VFIO_PCI_NUM_REGIONS +
|
2022-04-11 16:13:39 +02:00
|
|
|
vgpu->num_regions);
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
|
i = info.index - VFIO_PCI_NUM_REGIONS;
|
|
|
|
|
|
|
|
|
|
info.offset =
|
|
|
|
|
VFIO_PCI_INDEX_TO_OFFSET(info.index);
|
2022-04-11 16:13:39 +02:00
|
|
|
info.size = vgpu->region[i].size;
|
|
|
|
|
info.flags = vgpu->region[i].flags;
|
2016-12-08 11:00:36 +08:00
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
cap_type.type = vgpu->region[i].type;
|
|
|
|
|
cap_type.subtype = vgpu->region[i].subtype;
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
|
ret = vfio_info_add_capability(&caps,
|
2017-12-12 12:59:39 -07:00
|
|
|
&cap_type.header,
|
|
|
|
|
sizeof(cap_type));
|
2016-12-08 11:00:36 +08:00
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((info.flags & VFIO_REGION_INFO_FLAG_CAPS) && sparse) {
|
|
|
|
|
switch (cap_type_id) {
|
|
|
|
|
case VFIO_REGION_INFO_CAP_SPARSE_MMAP:
|
|
|
|
|
ret = vfio_info_add_capability(&caps,
|
2019-05-24 12:14:21 -05:00
|
|
|
&sparse->header,
|
|
|
|
|
struct_size(sparse, areas,
|
|
|
|
|
sparse->nr_areas));
|
2018-08-08 23:10:57 +08:00
|
|
|
if (ret) {
|
|
|
|
|
kfree(sparse);
|
2016-12-08 11:00:36 +08:00
|
|
|
return ret;
|
2018-08-08 23:10:57 +08:00
|
|
|
}
|
2016-12-08 11:00:36 +08:00
|
|
|
break;
|
|
|
|
|
default:
|
2018-08-08 23:10:57 +08:00
|
|
|
kfree(sparse);
|
2016-12-08 11:00:36 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (caps.size) {
|
2017-11-20 15:31:16 +08:00
|
|
|
info.flags |= VFIO_REGION_INFO_FLAG_CAPS;
|
2016-12-08 11:00:36 +08:00
|
|
|
if (info.argsz < sizeof(info) + caps.size) {
|
|
|
|
|
info.argsz = sizeof(info) + caps.size;
|
|
|
|
|
info.cap_offset = 0;
|
|
|
|
|
} else {
|
|
|
|
|
vfio_info_cap_shift(&caps, sizeof(info));
|
|
|
|
|
if (copy_to_user((void __user *)arg +
|
|
|
|
|
sizeof(info), caps.buf,
|
|
|
|
|
caps.size)) {
|
|
|
|
|
kfree(caps.buf);
|
2018-08-08 23:10:57 +08:00
|
|
|
kfree(sparse);
|
2016-12-08 11:00:36 +08:00
|
|
|
return -EFAULT;
|
|
|
|
|
}
|
|
|
|
|
info.cap_offset = sizeof(info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kfree(caps.buf);
|
|
|
|
|
}
|
|
|
|
|
|
2018-08-08 23:10:57 +08:00
|
|
|
kfree(sparse);
|
2016-12-08 11:00:36 +08:00
|
|
|
return copy_to_user((void __user *)arg, &info, minsz) ?
|
|
|
|
|
-EFAULT : 0;
|
|
|
|
|
} else if (cmd == VFIO_DEVICE_GET_IRQ_INFO) {
|
|
|
|
|
struct vfio_irq_info info;
|
|
|
|
|
|
|
|
|
|
minsz = offsetofend(struct vfio_irq_info, count);
|
|
|
|
|
|
|
|
|
|
if (copy_from_user(&info, (void __user *)arg, minsz))
|
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
|
|
if (info.argsz < minsz || info.index >= VFIO_PCI_NUM_IRQS)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
switch (info.index) {
|
|
|
|
|
case VFIO_PCI_INTX_IRQ_INDEX:
|
|
|
|
|
case VFIO_PCI_MSI_IRQ_INDEX:
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
info.flags = VFIO_IRQ_INFO_EVENTFD;
|
|
|
|
|
|
|
|
|
|
info.count = intel_vgpu_get_irq_count(vgpu, info.index);
|
|
|
|
|
|
|
|
|
|
if (info.index == VFIO_PCI_INTX_IRQ_INDEX)
|
|
|
|
|
info.flags |= (VFIO_IRQ_INFO_MASKABLE |
|
|
|
|
|
VFIO_IRQ_INFO_AUTOMASKED);
|
|
|
|
|
else
|
|
|
|
|
info.flags |= VFIO_IRQ_INFO_NORESIZE;
|
|
|
|
|
|
|
|
|
|
return copy_to_user((void __user *)arg, &info, minsz) ?
|
|
|
|
|
-EFAULT : 0;
|
|
|
|
|
} else if (cmd == VFIO_DEVICE_SET_IRQS) {
|
|
|
|
|
struct vfio_irq_set hdr;
|
|
|
|
|
u8 *data = NULL;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
size_t data_size = 0;
|
|
|
|
|
|
|
|
|
|
minsz = offsetofend(struct vfio_irq_set, count);
|
|
|
|
|
|
|
|
|
|
if (copy_from_user(&hdr, (void __user *)arg, minsz))
|
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
|
|
if (!(hdr.flags & VFIO_IRQ_SET_DATA_NONE)) {
|
|
|
|
|
int max = intel_vgpu_get_irq_count(vgpu, hdr.index);
|
|
|
|
|
|
|
|
|
|
ret = vfio_set_irqs_validate_and_prepare(&hdr, max,
|
|
|
|
|
VFIO_PCI_NUM_IRQS, &data_size);
|
|
|
|
|
if (ret) {
|
2017-03-10 04:26:53 -05:00
|
|
|
gvt_vgpu_err("intel:vfio_set_irqs_validate_and_prepare failed\n");
|
2016-12-08 11:00:36 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
|
|
|
|
if (data_size) {
|
|
|
|
|
data = memdup_user((void __user *)(arg + minsz),
|
|
|
|
|
data_size);
|
|
|
|
|
if (IS_ERR(data))
|
|
|
|
|
return PTR_ERR(data);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ret = intel_vgpu_set_irqs(vgpu, hdr.flags, hdr.index,
|
|
|
|
|
hdr.start, hdr.count, data);
|
|
|
|
|
kfree(data);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
} else if (cmd == VFIO_DEVICE_RESET) {
|
2022-04-11 16:13:36 +02:00
|
|
|
intel_gvt_reset_vgpu(vgpu);
|
2016-12-08 11:00:36 +08:00
|
|
|
return 0;
|
2017-11-23 16:26:36 +08:00
|
|
|
} else if (cmd == VFIO_DEVICE_QUERY_GFX_PLANE) {
|
|
|
|
|
struct vfio_device_gfx_plane_info dmabuf;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
minsz = offsetofend(struct vfio_device_gfx_plane_info,
|
|
|
|
|
dmabuf_id);
|
|
|
|
|
if (copy_from_user(&dmabuf, (void __user *)arg, minsz))
|
|
|
|
|
return -EFAULT;
|
|
|
|
|
if (dmabuf.argsz < minsz)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
2022-04-11 16:13:36 +02:00
|
|
|
ret = intel_vgpu_query_plane(vgpu, &dmabuf);
|
2017-11-23 16:26:36 +08:00
|
|
|
if (ret != 0)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
return copy_to_user((void __user *)arg, &dmabuf, minsz) ?
|
|
|
|
|
-EFAULT : 0;
|
|
|
|
|
} else if (cmd == VFIO_DEVICE_GET_GFX_DMABUF) {
|
|
|
|
|
__u32 dmabuf_id;
|
|
|
|
|
|
|
|
|
|
if (get_user(dmabuf_id, (__u32 __user *)arg))
|
|
|
|
|
return -EFAULT;
|
2022-04-11 16:13:36 +02:00
|
|
|
return intel_vgpu_get_dmabuf(vgpu, dmabuf_id);
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
2018-03-21 15:08:47 +01:00
|
|
|
return -ENOTTY;
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
2017-03-16 18:06:39 +08:00
|
|
|
static ssize_t
|
|
|
|
|
vgpu_id_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
|
char *buf)
|
|
|
|
|
{
|
2022-04-11 16:13:57 +02:00
|
|
|
struct intel_vgpu *vgpu = dev_get_drvdata(dev);
|
2017-03-16 18:06:39 +08:00
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
return sprintf(buf, "%d\n", vgpu->id);
|
2017-03-16 18:06:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static DEVICE_ATTR_RO(vgpu_id);
|
|
|
|
|
|
|
|
|
|
static struct attribute *intel_vgpu_attrs[] = {
|
|
|
|
|
&dev_attr_vgpu_id.attr,
|
|
|
|
|
NULL
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct attribute_group intel_vgpu_group = {
|
|
|
|
|
.name = "intel_vgpu",
|
|
|
|
|
.attrs = intel_vgpu_attrs,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const struct attribute_group *intel_vgpu_groups[] = {
|
|
|
|
|
&intel_vgpu_group,
|
|
|
|
|
NULL,
|
|
|
|
|
};
|
|
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
static const struct vfio_device_ops intel_vgpu_dev_ops = {
|
|
|
|
|
.open_device = intel_vgpu_open_device,
|
|
|
|
|
.close_device = intel_vgpu_close_device,
|
|
|
|
|
.read = intel_vgpu_read,
|
|
|
|
|
.write = intel_vgpu_write,
|
|
|
|
|
.mmap = intel_vgpu_mmap,
|
|
|
|
|
.ioctl = intel_vgpu_ioctl,
|
|
|
|
|
};
|
2016-12-08 11:00:36 +08:00
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
static int intel_vgpu_probe(struct mdev_device *mdev)
|
|
|
|
|
{
|
|
|
|
|
struct device *pdev = mdev_parent_dev(mdev);
|
|
|
|
|
struct intel_gvt *gvt = kdev_to_i915(pdev)->gvt;
|
|
|
|
|
struct intel_vgpu_type *type;
|
|
|
|
|
struct intel_vgpu *vgpu;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
type = &gvt->types[mdev_get_type_group_id(mdev)];
|
|
|
|
|
if (!type)
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
|
|
vgpu = intel_gvt_create_vgpu(gvt, type);
|
|
|
|
|
if (IS_ERR(vgpu)) {
|
|
|
|
|
gvt_err("failed to create intel vgpu: %ld\n", PTR_ERR(vgpu));
|
|
|
|
|
return PTR_ERR(vgpu);
|
|
|
|
|
}
|
2016-12-08 11:00:36 +08:00
|
|
|
|
2022-04-11 16:13:57 +02:00
|
|
|
vfio_init_group_dev(&vgpu->vfio_device, &mdev->dev,
|
|
|
|
|
&intel_vgpu_dev_ops);
|
|
|
|
|
|
|
|
|
|
dev_set_drvdata(&mdev->dev, vgpu);
|
|
|
|
|
ret = vfio_register_emulated_iommu_dev(&vgpu->vfio_device);
|
|
|
|
|
if (ret) {
|
|
|
|
|
intel_gvt_destroy_vgpu(vgpu);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n",
|
|
|
|
|
dev_name(mdev_dev(mdev)));
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_vgpu_remove(struct mdev_device *mdev)
|
|
|
|
|
{
|
|
|
|
|
struct intel_vgpu *vgpu = dev_get_drvdata(&mdev->dev);
|
|
|
|
|
|
|
|
|
|
if (WARN_ON_ONCE(vgpu->attached))
|
|
|
|
|
return;
|
|
|
|
|
intel_gvt_destroy_vgpu(vgpu);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static struct mdev_driver intel_vgpu_mdev_driver = {
|
|
|
|
|
.driver = {
|
|
|
|
|
.name = "intel_vgpu_mdev",
|
|
|
|
|
.owner = THIS_MODULE,
|
|
|
|
|
.dev_groups = intel_vgpu_groups,
|
|
|
|
|
},
|
|
|
|
|
.probe = intel_vgpu_probe,
|
|
|
|
|
.remove = intel_vgpu_remove,
|
|
|
|
|
.supported_type_groups = gvt_vgpu_type_groups,
|
2016-12-08 11:00:36 +08:00
|
|
|
};
|
|
|
|
|
|
2022-04-11 16:13:49 +02:00
|
|
|
int intel_gvt_page_track_add(struct intel_vgpu *info, u64 gfn)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
2022-05-19 14:33:11 -04:00
|
|
|
struct kvm *kvm = info->vfio_device.kvm;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
struct kvm_memory_slot *slot;
|
|
|
|
|
int idx;
|
|
|
|
|
|
2022-04-11 16:13:41 +02:00
|
|
|
if (!info->attached)
|
2016-12-08 11:00:36 +08:00
|
|
|
return -ESRCH;
|
|
|
|
|
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
idx = srcu_read_lock(&kvm->srcu);
|
|
|
|
|
slot = gfn_to_memslot(kvm, gfn);
|
2016-12-16 10:51:05 +08:00
|
|
|
if (!slot) {
|
|
|
|
|
srcu_read_unlock(&kvm->srcu, idx);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2021-02-08 06:29:28 -05:00
|
|
|
write_lock(&kvm->mmu_lock);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
|
|
|
|
if (kvmgt_gfn_is_write_protected(info, gfn))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
kvm_slot_page_track_add_page(kvm, slot, gfn, KVM_PAGE_TRACK_WRITE);
|
|
|
|
|
kvmgt_protect_table_add(info, gfn);
|
|
|
|
|
|
|
|
|
|
out:
|
2021-02-08 06:29:28 -05:00
|
|
|
write_unlock(&kvm->mmu_lock);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
srcu_read_unlock(&kvm->srcu, idx);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:49 +02:00
|
|
|
int intel_gvt_page_track_remove(struct intel_vgpu *info, u64 gfn)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
2022-05-19 14:33:11 -04:00
|
|
|
struct kvm *kvm = info->vfio_device.kvm;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
struct kvm_memory_slot *slot;
|
|
|
|
|
int idx;
|
|
|
|
|
|
2022-04-11 16:13:41 +02:00
|
|
|
if (!info->attached)
|
2016-12-08 11:00:36 +08:00
|
|
|
return 0;
|
|
|
|
|
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
idx = srcu_read_lock(&kvm->srcu);
|
|
|
|
|
slot = gfn_to_memslot(kvm, gfn);
|
2016-12-16 10:51:05 +08:00
|
|
|
if (!slot) {
|
|
|
|
|
srcu_read_unlock(&kvm->srcu, idx);
|
|
|
|
|
return -EINVAL;
|
|
|
|
|
}
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2021-02-08 06:29:28 -05:00
|
|
|
write_lock(&kvm->mmu_lock);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
|
|
|
|
if (!kvmgt_gfn_is_write_protected(info, gfn))
|
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
|
|
kvm_slot_page_track_remove_page(kvm, slot, gfn, KVM_PAGE_TRACK_WRITE);
|
|
|
|
|
kvmgt_protect_table_del(info, gfn);
|
|
|
|
|
|
|
|
|
|
out:
|
2021-02-08 06:29:28 -05:00
|
|
|
write_unlock(&kvm->mmu_lock);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
srcu_read_unlock(&kvm->srcu, idx);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void kvmgt_page_track_write(struct kvm_vcpu *vcpu, gpa_t gpa,
|
|
|
|
|
const u8 *val, int len,
|
|
|
|
|
struct kvm_page_track_notifier_node *node)
|
|
|
|
|
{
|
2022-04-11 16:13:40 +02:00
|
|
|
struct intel_vgpu *info =
|
|
|
|
|
container_of(node, struct intel_vgpu, track_node);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
|
|
|
|
if (kvmgt_gfn_is_write_protected(info, gpa_to_gfn(gpa)))
|
2022-04-11 16:13:40 +02:00
|
|
|
intel_vgpu_page_track_handler(info, gpa,
|
2017-12-18 11:58:46 +08:00
|
|
|
(void *)val, len);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void kvmgt_page_track_flush_slot(struct kvm *kvm,
|
|
|
|
|
struct kvm_memory_slot *slot,
|
|
|
|
|
struct kvm_page_track_notifier_node *node)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
gfn_t gfn;
|
2022-04-11 16:13:40 +02:00
|
|
|
struct intel_vgpu *info =
|
|
|
|
|
container_of(node, struct intel_vgpu, track_node);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2021-02-08 06:29:28 -05:00
|
|
|
write_lock(&kvm->mmu_lock);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
for (i = 0; i < slot->npages; i++) {
|
|
|
|
|
gfn = slot->base_gfn + i;
|
|
|
|
|
if (kvmgt_gfn_is_write_protected(info, gfn)) {
|
|
|
|
|
kvm_slot_page_track_remove_page(kvm, slot, gfn,
|
|
|
|
|
KVM_PAGE_TRACK_WRITE);
|
|
|
|
|
kvmgt_protect_table_del(info, gfn);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-02-08 06:29:28 -05:00
|
|
|
write_unlock(&kvm->mmu_lock);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:45 +02:00
|
|
|
void intel_vgpu_detach_regions(struct intel_vgpu *vgpu)
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
{
|
2019-01-14 18:43:39 +08:00
|
|
|
int i;
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
if (!vgpu->region)
|
2019-01-14 18:43:39 +08:00
|
|
|
return;
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
for (i = 0; i < vgpu->num_regions; i++)
|
|
|
|
|
if (vgpu->region[i].ops->release)
|
|
|
|
|
vgpu->region[i].ops->release(vgpu,
|
|
|
|
|
&vgpu->region[i]);
|
|
|
|
|
vgpu->num_regions = 0;
|
|
|
|
|
kfree(vgpu->region);
|
|
|
|
|
vgpu->region = NULL;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:50 +02:00
|
|
|
int intel_gvt_dma_map_guest_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
2018-05-15 10:35:42 +08:00
|
|
|
unsigned long size, dma_addr_t *dma_addr)
|
2018-03-01 15:49:59 +08:00
|
|
|
{
|
|
|
|
|
struct gvt_dma *entry;
|
|
|
|
|
int ret;
|
|
|
|
|
|
2022-04-11 16:13:41 +02:00
|
|
|
if (!vgpu->attached)
|
2018-03-01 15:49:59 +08:00
|
|
|
return -EINVAL;
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_lock(&vgpu->cache_lock);
|
2018-03-01 15:49:59 +08:00
|
|
|
|
2020-02-17 17:38:58 +01:00
|
|
|
entry = __gvt_cache_find_gfn(vgpu, gfn);
|
2018-03-01 15:49:59 +08:00
|
|
|
if (!entry) {
|
2019-07-18 01:10:24 +08:00
|
|
|
ret = gvt_dma_map_page(vgpu, gfn, dma_addr, size);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto err_unlock;
|
|
|
|
|
|
2020-02-17 17:38:58 +01:00
|
|
|
ret = __gvt_cache_add(vgpu, gfn, *dma_addr, size);
|
2019-07-18 01:10:24 +08:00
|
|
|
if (ret)
|
|
|
|
|
goto err_unmap;
|
|
|
|
|
} else if (entry->size != size) {
|
|
|
|
|
/* the same gfn with different size: unmap and re-map */
|
|
|
|
|
gvt_dma_unmap_page(vgpu, gfn, entry->dma_addr, entry->size);
|
|
|
|
|
__gvt_cache_remove_entry(vgpu, entry);
|
|
|
|
|
|
2018-05-15 10:35:42 +08:00
|
|
|
ret = gvt_dma_map_page(vgpu, gfn, dma_addr, size);
|
2018-03-12 15:12:34 +08:00
|
|
|
if (ret)
|
|
|
|
|
goto err_unlock;
|
|
|
|
|
|
2020-02-17 17:38:58 +01:00
|
|
|
ret = __gvt_cache_add(vgpu, gfn, *dma_addr, size);
|
2018-03-12 15:12:34 +08:00
|
|
|
if (ret)
|
|
|
|
|
goto err_unmap;
|
2018-03-01 15:49:59 +08:00
|
|
|
} else {
|
|
|
|
|
kref_get(&entry->ref);
|
|
|
|
|
*dma_addr = entry->dma_addr;
|
2017-02-14 17:15:54 +08:00
|
|
|
}
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_unlock(&vgpu->cache_lock);
|
2018-03-01 15:49:59 +08:00
|
|
|
return 0;
|
2018-03-12 15:12:34 +08:00
|
|
|
|
|
|
|
|
err_unmap:
|
2018-05-15 10:35:42 +08:00
|
|
|
gvt_dma_unmap_page(vgpu, gfn, *dma_addr, size);
|
2018-03-12 15:12:34 +08:00
|
|
|
err_unlock:
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_unlock(&vgpu->cache_lock);
|
2018-03-12 15:12:34 +08:00
|
|
|
return ret;
|
2018-03-01 15:49:59 +08:00
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:51 +02:00
|
|
|
int intel_gvt_dma_pin_guest_page(struct intel_vgpu *vgpu, dma_addr_t dma_addr)
|
2019-12-13 11:23:14 +08:00
|
|
|
{
|
|
|
|
|
struct gvt_dma *entry;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
2022-04-11 16:13:41 +02:00
|
|
|
if (!vgpu->attached)
|
2019-12-13 11:23:14 +08:00
|
|
|
return -ENODEV;
|
|
|
|
|
|
2022-04-11 16:13:40 +02:00
|
|
|
mutex_lock(&vgpu->cache_lock);
|
|
|
|
|
entry = __gvt_cache_find_dma_addr(vgpu, dma_addr);
|
2019-12-13 11:23:14 +08:00
|
|
|
if (entry)
|
|
|
|
|
kref_get(&entry->ref);
|
|
|
|
|
else
|
|
|
|
|
ret = -ENOMEM;
|
2022-04-11 16:13:40 +02:00
|
|
|
mutex_unlock(&vgpu->cache_lock);
|
2019-12-13 11:23:14 +08:00
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
static void __gvt_dma_release(struct kref *ref)
|
|
|
|
|
{
|
|
|
|
|
struct gvt_dma *entry = container_of(ref, typeof(*entry), ref);
|
|
|
|
|
|
2018-05-15 10:35:42 +08:00
|
|
|
gvt_dma_unmap_page(entry->vgpu, entry->gfn, entry->dma_addr,
|
|
|
|
|
entry->size);
|
2018-03-01 15:49:59 +08:00
|
|
|
__gvt_cache_remove_entry(entry->vgpu, entry);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:50 +02:00
|
|
|
void intel_gvt_dma_unmap_guest_page(struct intel_vgpu *vgpu,
|
2022-04-11 16:13:41 +02:00
|
|
|
dma_addr_t dma_addr)
|
2018-03-01 15:49:59 +08:00
|
|
|
{
|
|
|
|
|
struct gvt_dma *entry;
|
|
|
|
|
|
2022-04-11 16:13:41 +02:00
|
|
|
if (!vgpu->attached)
|
2018-03-01 15:49:59 +08:00
|
|
|
return;
|
|
|
|
|
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_lock(&vgpu->cache_lock);
|
2020-02-17 17:38:58 +01:00
|
|
|
entry = __gvt_cache_find_dma_addr(vgpu, dma_addr);
|
2018-03-01 15:49:59 +08:00
|
|
|
if (entry)
|
|
|
|
|
kref_put(&entry->ref, __gvt_dma_release);
|
2022-04-11 16:13:39 +02:00
|
|
|
mutex_unlock(&vgpu->cache_lock);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
2022-04-11 16:13:58 +02:00
|
|
|
static void init_device_info(struct intel_gvt *gvt)
|
|
|
|
|
{
|
|
|
|
|
struct intel_gvt_device_info *info = &gvt->device_info;
|
|
|
|
|
struct pci_dev *pdev = to_pci_dev(gvt->gt->i915->drm.dev);
|
|
|
|
|
|
|
|
|
|
info->max_support_vgpus = 8;
|
|
|
|
|
info->cfg_space_size = PCI_CFG_SPACE_EXP_SIZE;
|
|
|
|
|
info->mmio_size = 2 * 1024 * 1024;
|
|
|
|
|
info->mmio_bar = 0;
|
|
|
|
|
info->gtt_start_offset = 8 * 1024 * 1024;
|
|
|
|
|
info->gtt_entry_size = 8;
|
|
|
|
|
info->gtt_entry_size_shift = 3;
|
|
|
|
|
info->gmadr_bytes_in_cmd = 8;
|
|
|
|
|
info->max_surface_size = 36 * 1024 * 1024;
|
|
|
|
|
info->msi_cap_offset = pdev->msi_cap;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_gvt_test_and_emulate_vblank(struct intel_gvt *gvt)
|
|
|
|
|
{
|
|
|
|
|
struct intel_vgpu *vgpu;
|
|
|
|
|
int id;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&gvt->lock);
|
|
|
|
|
idr_for_each_entry((&(gvt)->vgpu_idr), (vgpu), (id)) {
|
|
|
|
|
if (test_and_clear_bit(INTEL_GVT_REQUEST_EMULATE_VBLANK + id,
|
|
|
|
|
(void *)&gvt->service_request)) {
|
|
|
|
|
if (vgpu->active)
|
|
|
|
|
intel_vgpu_emulate_vblank(vgpu);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
mutex_unlock(&gvt->lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int gvt_service_thread(void *data)
|
|
|
|
|
{
|
|
|
|
|
struct intel_gvt *gvt = (struct intel_gvt *)data;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
gvt_dbg_core("service thread start\n");
|
|
|
|
|
|
|
|
|
|
while (!kthread_should_stop()) {
|
|
|
|
|
ret = wait_event_interruptible(gvt->service_thread_wq,
|
|
|
|
|
kthread_should_stop() || gvt->service_request);
|
|
|
|
|
|
|
|
|
|
if (kthread_should_stop())
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
if (WARN_ONCE(ret, "service thread is waken up by signal.\n"))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
intel_gvt_test_and_emulate_vblank(gvt);
|
|
|
|
|
|
|
|
|
|
if (test_bit(INTEL_GVT_REQUEST_SCHED,
|
|
|
|
|
(void *)&gvt->service_request) ||
|
|
|
|
|
test_bit(INTEL_GVT_REQUEST_EVENT_SCHED,
|
|
|
|
|
(void *)&gvt->service_request)) {
|
|
|
|
|
intel_gvt_schedule(gvt);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void clean_service_thread(struct intel_gvt *gvt)
|
|
|
|
|
{
|
|
|
|
|
kthread_stop(gvt->service_thread);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int init_service_thread(struct intel_gvt *gvt)
|
|
|
|
|
{
|
|
|
|
|
init_waitqueue_head(&gvt->service_thread_wq);
|
|
|
|
|
|
|
|
|
|
gvt->service_thread = kthread_run(gvt_service_thread,
|
|
|
|
|
gvt, "gvt_service_thread");
|
|
|
|
|
if (IS_ERR(gvt->service_thread)) {
|
|
|
|
|
gvt_err("fail to start service thread.\n");
|
|
|
|
|
return PTR_ERR(gvt->service_thread);
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* intel_gvt_clean_device - clean a GVT device
|
|
|
|
|
* @i915: i915 private
|
|
|
|
|
*
|
|
|
|
|
* This function is called at the driver unloading stage, to free the
|
|
|
|
|
* resources owned by a GVT device.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
static void intel_gvt_clean_device(struct drm_i915_private *i915)
|
|
|
|
|
{
|
|
|
|
|
struct intel_gvt *gvt = fetch_and_zero(&i915->gvt);
|
|
|
|
|
|
|
|
|
|
if (drm_WARN_ON(&i915->drm, !gvt))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
mdev_unregister_device(i915->drm.dev);
|
|
|
|
|
intel_gvt_cleanup_vgpu_type_groups(gvt);
|
|
|
|
|
intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
|
|
|
|
|
intel_gvt_clean_vgpu_types(gvt);
|
|
|
|
|
|
|
|
|
|
intel_gvt_debugfs_clean(gvt);
|
|
|
|
|
clean_service_thread(gvt);
|
|
|
|
|
intel_gvt_clean_cmd_parser(gvt);
|
|
|
|
|
intel_gvt_clean_sched_policy(gvt);
|
|
|
|
|
intel_gvt_clean_workload_scheduler(gvt);
|
|
|
|
|
intel_gvt_clean_gtt(gvt);
|
|
|
|
|
intel_gvt_free_firmware(gvt);
|
|
|
|
|
intel_gvt_clean_mmio_info(gvt);
|
|
|
|
|
idr_destroy(&gvt->vgpu_idr);
|
|
|
|
|
|
|
|
|
|
kfree(i915->gvt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* intel_gvt_init_device - initialize a GVT device
|
|
|
|
|
* @i915: drm i915 private data
|
|
|
|
|
*
|
|
|
|
|
* This function is called at the initialization stage, to initialize
|
|
|
|
|
* necessary GVT components.
|
|
|
|
|
*
|
|
|
|
|
* Returns:
|
|
|
|
|
* Zero on success, negative error code if failed.
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
static int intel_gvt_init_device(struct drm_i915_private *i915)
|
|
|
|
|
{
|
|
|
|
|
struct intel_gvt *gvt;
|
|
|
|
|
struct intel_vgpu *vgpu;
|
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
if (drm_WARN_ON(&i915->drm, i915->gvt))
|
|
|
|
|
return -EEXIST;
|
|
|
|
|
|
|
|
|
|
gvt = kzalloc(sizeof(struct intel_gvt), GFP_KERNEL);
|
|
|
|
|
if (!gvt)
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
|
|
gvt_dbg_core("init gvt device\n");
|
|
|
|
|
|
|
|
|
|
idr_init_base(&gvt->vgpu_idr, 1);
|
|
|
|
|
spin_lock_init(&gvt->scheduler.mmio_context_lock);
|
|
|
|
|
mutex_init(&gvt->lock);
|
|
|
|
|
mutex_init(&gvt->sched_lock);
|
|
|
|
|
gvt->gt = to_gt(i915);
|
|
|
|
|
i915->gvt = gvt;
|
|
|
|
|
|
|
|
|
|
init_device_info(gvt);
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_setup_mmio_info(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_clean_idr;
|
|
|
|
|
|
|
|
|
|
intel_gvt_init_engine_mmio_context(gvt);
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_load_firmware(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_clean_mmio_info;
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_init_irq(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_free_firmware;
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_init_gtt(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_free_firmware;
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_init_workload_scheduler(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_clean_gtt;
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_init_sched_policy(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_clean_workload_scheduler;
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_init_cmd_parser(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_clean_sched_policy;
|
|
|
|
|
|
|
|
|
|
ret = init_service_thread(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_clean_cmd_parser;
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_init_vgpu_types(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_clean_thread;
|
|
|
|
|
|
|
|
|
|
vgpu = intel_gvt_create_idle_vgpu(gvt);
|
|
|
|
|
if (IS_ERR(vgpu)) {
|
|
|
|
|
ret = PTR_ERR(vgpu);
|
|
|
|
|
gvt_err("failed to create idle vgpu\n");
|
|
|
|
|
goto out_clean_types;
|
|
|
|
|
}
|
|
|
|
|
gvt->idle_vgpu = vgpu;
|
|
|
|
|
|
|
|
|
|
intel_gvt_debugfs_init(gvt);
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_init_vgpu_type_groups(gvt);
|
|
|
|
|
if (ret)
|
|
|
|
|
goto out_destroy_idle_vgpu;
|
|
|
|
|
|
2022-04-11 16:14:01 +02:00
|
|
|
ret = mdev_register_device(i915->drm.dev, &intel_vgpu_mdev_driver);
|
2022-04-11 16:13:58 +02:00
|
|
|
if (ret)
|
|
|
|
|
goto out_cleanup_vgpu_type_groups;
|
|
|
|
|
|
|
|
|
|
gvt_dbg_core("gvt device initialization is done\n");
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
out_cleanup_vgpu_type_groups:
|
|
|
|
|
intel_gvt_cleanup_vgpu_type_groups(gvt);
|
|
|
|
|
out_destroy_idle_vgpu:
|
|
|
|
|
intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
|
|
|
|
|
intel_gvt_debugfs_clean(gvt);
|
|
|
|
|
out_clean_types:
|
|
|
|
|
intel_gvt_clean_vgpu_types(gvt);
|
|
|
|
|
out_clean_thread:
|
|
|
|
|
clean_service_thread(gvt);
|
|
|
|
|
out_clean_cmd_parser:
|
|
|
|
|
intel_gvt_clean_cmd_parser(gvt);
|
|
|
|
|
out_clean_sched_policy:
|
|
|
|
|
intel_gvt_clean_sched_policy(gvt);
|
|
|
|
|
out_clean_workload_scheduler:
|
|
|
|
|
intel_gvt_clean_workload_scheduler(gvt);
|
|
|
|
|
out_clean_gtt:
|
|
|
|
|
intel_gvt_clean_gtt(gvt);
|
|
|
|
|
out_free_firmware:
|
|
|
|
|
intel_gvt_free_firmware(gvt);
|
|
|
|
|
out_clean_mmio_info:
|
|
|
|
|
intel_gvt_clean_mmio_info(gvt);
|
|
|
|
|
out_clean_idr:
|
|
|
|
|
idr_destroy(&gvt->vgpu_idr);
|
|
|
|
|
kfree(gvt);
|
|
|
|
|
i915->gvt = NULL;
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void intel_gvt_pm_resume(struct drm_i915_private *i915)
|
|
|
|
|
{
|
|
|
|
|
struct intel_gvt *gvt = i915->gvt;
|
|
|
|
|
|
|
|
|
|
intel_gvt_restore_fence(gvt);
|
|
|
|
|
intel_gvt_restore_mmio(gvt);
|
|
|
|
|
intel_gvt_restore_ggtt(gvt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static const struct intel_vgpu_ops intel_gvt_vgpu_ops = {
|
|
|
|
|
.init_device = intel_gvt_init_device,
|
|
|
|
|
.clean_device = intel_gvt_clean_device,
|
|
|
|
|
.pm_resume = intel_gvt_pm_resume,
|
|
|
|
|
};
|
|
|
|
|
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
static int __init kvmgt_init(void)
|
|
|
|
|
{
|
2022-04-11 16:13:57 +02:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
|
|
ret = intel_gvt_set_ops(&intel_gvt_vgpu_ops);
|
|
|
|
|
if (ret)
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
ret = mdev_register_driver(&intel_vgpu_mdev_driver);
|
|
|
|
|
if (ret)
|
|
|
|
|
intel_gvt_clear_ops(&intel_gvt_vgpu_ops);
|
|
|
|
|
return ret;
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __exit kvmgt_exit(void)
|
|
|
|
|
{
|
2022-04-11 16:13:57 +02:00
|
|
|
mdev_unregister_driver(&intel_vgpu_mdev_driver);
|
2022-04-11 16:13:35 +02:00
|
|
|
intel_gvt_clear_ops(&intel_gvt_vgpu_ops);
|
drm/i915/gvt: add KVMGT support
KVMGT is the MPT implementation based on VFIO/KVM. It provides
a kvmgt_mpt ops to gvt for vGPU access mediation, e.g. to
mediate and emulate the MMIO accesses, to inject interrupts
to vGPU user, to intercept the GTT writing and replace it with
DMA-able address, to write-protect guest PPGTT table for
shadowing synchronization, etc. This patch provides the MPT
implementation for GVT, not yet functional due to theabsence
of mdev.
It's built as kvmgt.ko, depends on vfio.ko, kvm.ko and mdev.ko,
and being required by i915.ko. To not introduce hard dependency
in i915.ko, we used indirect symbol reference. But that means
users have to include kvmgt.ko into init ramdisk if their
i915.ko is included.
Signed-off-by: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Xiaoguang Chen <xiaoguang.chen@intel.com>
Signed-off-by: Jike Song <jike.song@intel.com>
Signed-off-by: Zhenyu Wang <zhenyuw@linux.intel.com>
2016-11-09 20:30:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
module_init(kvmgt_init);
|
|
|
|
|
module_exit(kvmgt_exit);
|
|
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL and additional rights");
|
|
|
|
|
MODULE_AUTHOR("Intel Corporation");
|