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
|
|
|
|
*
|
|
|
|
* Copyright(c) 2014-2016 Intel Corporation. All rights reserved.
|
|
|
|
*
|
|
|
|
* 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>
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <linux/init.h>
|
|
|
|
#include <linux/device.h>
|
|
|
|
#include <linux/mm.h>
|
2016-12-08 11:00:35 +08:00
|
|
|
#include <linux/mmu_context.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>
|
|
|
|
#include <linux/kvm_host.h>
|
|
|
|
#include <linux/vfio.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
|
|
|
|
|
|
|
#include "i915_drv.h"
|
|
|
|
#include "gvt.h"
|
|
|
|
|
|
|
|
static const struct intel_gvt_ops *intel_gvt_ops;
|
|
|
|
|
|
|
|
/* 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)
|
|
|
|
|
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
|
|
|
};
|
|
|
|
|
|
|
|
struct kvmgt_pgfn {
|
|
|
|
gfn_t gfn;
|
|
|
|
struct hlist_node hnode;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct kvmgt_guest_info {
|
|
|
|
struct kvm *kvm;
|
|
|
|
struct intel_vgpu *vgpu;
|
|
|
|
struct kvm_page_track_notifier_node track_node;
|
|
|
|
#define NR_BKT (1 << 18)
|
|
|
|
struct hlist_head ptable[NR_BKT];
|
|
|
|
#undef NR_BKT
|
2018-03-05 15:30:34 +08:00
|
|
|
struct dentry *debugfs_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
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
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
|
|
|
};
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
static inline bool handle_valid(unsigned long handle)
|
|
|
|
{
|
|
|
|
return !!(handle & ~0xff);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvmgt_guest_init(struct mdev_device *mdev);
|
|
|
|
static void intel_vgpu_release_work(struct work_struct *work);
|
|
|
|
static bool kvmgt_guest_exit(struct kvmgt_guest_info *info);
|
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
static int gvt_dma_map_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
|
|
|
dma_addr_t *dma_addr)
|
2017-02-09 11:38:01 +08:00
|
|
|
{
|
|
|
|
struct device *dev = &vgpu->gvt->dev_priv->drm.pdev->dev;
|
2018-03-01 15:49:59 +08:00
|
|
|
struct page *page;
|
|
|
|
unsigned long pfn;
|
|
|
|
int ret;
|
2017-02-09 11:38:01 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
/* Pin the page first. */
|
|
|
|
ret = vfio_pin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1,
|
|
|
|
IOMMU_READ | IOMMU_WRITE, &pfn);
|
|
|
|
if (ret != 1) {
|
|
|
|
gvt_vgpu_err("vfio_pin_pages failed for gfn 0x%lx: %d\n",
|
|
|
|
gfn, ret);
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
2017-02-09 11:38:01 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
/* Setup DMA mapping. */
|
2017-03-01 14:34:52 +08:00
|
|
|
page = pfn_to_page(pfn);
|
2018-03-01 15:49:59 +08:00
|
|
|
*dma_addr = dma_map_page(dev, page, 0, PAGE_SIZE,
|
|
|
|
PCI_DMA_BIDIRECTIONAL);
|
|
|
|
if (dma_mapping_error(dev, *dma_addr)) {
|
|
|
|
gvt_vgpu_err("DMA mapping failed for gfn 0x%lx\n", gfn);
|
|
|
|
vfio_unpin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1);
|
2017-02-09 11:38:01 +08:00
|
|
|
return -ENOMEM;
|
2018-03-01 15:49:59 +08:00
|
|
|
}
|
2017-02-09 11:38:01 +08:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
static void gvt_dma_unmap_page(struct intel_vgpu *vgpu, unsigned long gfn,
|
|
|
|
dma_addr_t dma_addr)
|
2017-02-09 11:38:01 +08:00
|
|
|
{
|
|
|
|
struct device *dev = &vgpu->gvt->dev_priv->drm.pdev->dev;
|
2018-03-01 15:49:59 +08:00
|
|
|
int ret;
|
2017-02-09 11:38:01 +08:00
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
dma_unmap_page(dev, dma_addr, PAGE_SIZE, PCI_DMA_BIDIRECTIONAL);
|
|
|
|
ret = vfio_unpin_pages(mdev_dev(vgpu->vdev.mdev), &gfn, 1);
|
|
|
|
WARN_ON(ret != 1);
|
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
|
|
|
{
|
2018-03-01 15:49:59 +08:00
|
|
|
struct rb_node *node = vgpu->vdev.dma_addr_cache.rb_node;
|
|
|
|
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
|
|
|
{
|
2018-03-01 15:49:59 +08:00
|
|
|
struct rb_node *node = vgpu->vdev.gfn_cache.rb_node;
|
|
|
|
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-01 15:49:59 +08:00
|
|
|
static void __gvt_cache_add(struct intel_vgpu *vgpu, gfn_t gfn,
|
|
|
|
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
|
|
|
{
|
|
|
|
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)
|
|
|
|
return;
|
|
|
|
|
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;
|
|
|
|
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. */
|
|
|
|
link = &vgpu->vdev.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);
|
|
|
|
rb_insert_color(&new->gfn_node, &vgpu->vdev.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;
|
|
|
|
link = &vgpu->vdev.dma_addr_cache.rb_node;
|
|
|
|
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);
|
|
|
|
rb_insert_color(&new->dma_addr_node, &vgpu->vdev.dma_addr_cache);
|
2018-03-05 15:30:34 +08:00
|
|
|
|
|
|
|
vgpu->vdev.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_remove_entry(struct intel_vgpu *vgpu,
|
|
|
|
struct gvt_dma *entry)
|
|
|
|
{
|
2018-03-01 15:49:59 +08:00
|
|
|
rb_erase(&entry->gfn_node, &vgpu->vdev.gfn_cache);
|
|
|
|
rb_erase(&entry->dma_addr_node, &vgpu->vdev.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);
|
2018-03-05 15:30:34 +08:00
|
|
|
vgpu->vdev.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 (;;) {
|
|
|
|
mutex_lock(&vgpu->vdev.cache_lock);
|
2018-03-01 15:49:59 +08:00
|
|
|
node = rb_first(&vgpu->vdev.gfn_cache);
|
2017-06-26 15:20:50 +08:00
|
|
|
if (!node) {
|
|
|
|
mutex_unlock(&vgpu->vdev.cache_lock);
|
|
|
|
break;
|
|
|
|
}
|
2018-03-01 15:49:59 +08:00
|
|
|
dma = rb_entry(node, struct gvt_dma, gfn_node);
|
|
|
|
gvt_dma_unmap_page(vgpu, dma->gfn, dma->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
|
|
|
__gvt_cache_remove_entry(vgpu, dma);
|
2017-06-26 15:20:50 +08:00
|
|
|
mutex_unlock(&vgpu->vdev.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)
|
|
|
|
{
|
|
|
|
vgpu->vdev.gfn_cache = RB_ROOT;
|
|
|
|
vgpu->vdev.dma_addr_cache = RB_ROOT;
|
2018-03-05 15:30:34 +08:00
|
|
|
vgpu->vdev.nr_cache_entries = 0;
|
2018-03-01 15:49:59 +08:00
|
|
|
mutex_init(&vgpu->vdev.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
|
|
|
static void kvmgt_protect_table_init(struct kvmgt_guest_info *info)
|
|
|
|
{
|
|
|
|
hash_init(info->ptable);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void kvmgt_protect_table_destroy(struct kvmgt_guest_info *info)
|
|
|
|
{
|
|
|
|
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 *
|
|
|
|
__kvmgt_protect_table_find(struct kvmgt_guest_info *info, gfn_t gfn)
|
|
|
|
{
|
|
|
|
struct kvmgt_pgfn *p, *res = NULL;
|
|
|
|
|
|
|
|
hash_for_each_possible(info->ptable, p, hnode, gfn) {
|
|
|
|
if (gfn == p->gfn) {
|
|
|
|
res = p;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool kvmgt_gfn_is_write_protected(struct kvmgt_guest_info *info,
|
|
|
|
gfn_t gfn)
|
|
|
|
{
|
|
|
|
struct kvmgt_pgfn *p;
|
|
|
|
|
|
|
|
p = __kvmgt_protect_table_find(info, gfn);
|
|
|
|
return !!p;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void kvmgt_protect_table_add(struct kvmgt_guest_info *info, gfn_t gfn)
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void kvmgt_protect_table_del(struct kvmgt_guest_info *info,
|
|
|
|
gfn_t gfn)
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
void *base = vgpu->vdev.region[i].data;
|
|
|
|
loff_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
|
|
|
|
|
|
|
|
if (pos >= vgpu->vdev.region[i].size || iswrite) {
|
|
|
|
gvt_vgpu_err("invalid op or offset for Intel vgpu OpRegion\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
count = min(count, (size_t)(vgpu->vdev.region[i].size - pos));
|
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
region = krealloc(vgpu->vdev.region,
|
|
|
|
(vgpu->vdev.num_regions + 1) * sizeof(*region),
|
|
|
|
GFP_KERNEL);
|
|
|
|
if (!region)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
vgpu->vdev.region = region;
|
|
|
|
vgpu->vdev.region[vgpu->vdev.num_regions].type = type;
|
|
|
|
vgpu->vdev.region[vgpu->vdev.num_regions].subtype = subtype;
|
|
|
|
vgpu->vdev.region[vgpu->vdev.num_regions].ops = ops;
|
|
|
|
vgpu->vdev.region[vgpu->vdev.num_regions].size = size;
|
|
|
|
vgpu->vdev.region[vgpu->vdev.num_regions].flags = flags;
|
|
|
|
vgpu->vdev.region[vgpu->vdev.num_regions].data = data;
|
|
|
|
vgpu->vdev.num_regions++;
|
2017-11-23 16:26:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvmgt_get_vfio_device(void *p_vgpu)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = (struct intel_vgpu *)p_vgpu;
|
2017-11-20 15:31:16 +08:00
|
|
|
|
2017-11-23 16:26:36 +08:00
|
|
|
vgpu->vdev.vfio_device = vfio_device_get_from_dev(
|
|
|
|
mdev_dev(vgpu->vdev.mdev));
|
|
|
|
if (!vgpu->vdev.vfio_device) {
|
|
|
|
gvt_vgpu_err("failed to get vfio device\n");
|
|
|
|
return -ENODEV;
|
|
|
|
}
|
2017-11-20 15:31:16 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-11-23 16:26:36 +08:00
|
|
|
|
2017-11-20 15:31:16 +08:00
|
|
|
static int kvmgt_set_opregion(void *p_vgpu)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = (struct intel_vgpu *)p_vgpu;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-11-23 16:26:36 +08:00
|
|
|
static void kvmgt_put_vfio_device(void *vgpu)
|
|
|
|
{
|
|
|
|
if (WARN_ON(!((struct intel_vgpu *)vgpu)->vdev.vfio_device))
|
|
|
|
return;
|
|
|
|
|
|
|
|
vfio_device_put(((struct intel_vgpu *)vgpu)->vdev.vfio_device);
|
|
|
|
}
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
static int intel_vgpu_create(struct kobject *kobj, struct mdev_device *mdev)
|
|
|
|
{
|
2017-03-10 17:26:53 +08:00
|
|
|
struct intel_vgpu *vgpu = NULL;
|
2016-12-08 11:00:36 +08:00
|
|
|
struct intel_vgpu_type *type;
|
|
|
|
struct device *pdev;
|
|
|
|
void *gvt;
|
2017-01-06 15:16:20 +08:00
|
|
|
int ret;
|
2016-12-08 11:00:36 +08:00
|
|
|
|
2016-12-30 23:13:41 +08:00
|
|
|
pdev = mdev_parent_dev(mdev);
|
2016-12-08 11:00:36 +08:00
|
|
|
gvt = kdev_to_i915(pdev)->gvt;
|
|
|
|
|
2017-09-28 11:03:03 +08:00
|
|
|
type = intel_gvt_ops->gvt_find_vgpu_type(gvt, kobject_name(kobj));
|
2016-12-08 11:00:36 +08:00
|
|
|
if (!type) {
|
2017-03-10 17:26:53 +08:00
|
|
|
gvt_vgpu_err("failed to find type %s to create\n",
|
2016-12-08 11:00:36 +08:00
|
|
|
kobject_name(kobj));
|
2017-01-06 15:16:20 +08:00
|
|
|
ret = -EINVAL;
|
|
|
|
goto out;
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
vgpu = intel_gvt_ops->vgpu_create(gvt, type);
|
|
|
|
if (IS_ERR_OR_NULL(vgpu)) {
|
2017-01-06 15:16:20 +08:00
|
|
|
ret = vgpu == NULL ? -EFAULT : PTR_ERR(vgpu);
|
2018-02-22 15:16:14 +08:00
|
|
|
gvt_err("failed to create intel vgpu: %d\n", ret);
|
2017-01-06 15:16:20 +08:00
|
|
|
goto out;
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
INIT_WORK(&vgpu->vdev.release_work, intel_vgpu_release_work);
|
|
|
|
|
|
|
|
vgpu->vdev.mdev = mdev;
|
|
|
|
mdev_set_drvdata(mdev, vgpu);
|
|
|
|
|
|
|
|
gvt_dbg_core("intel_vgpu_create succeeded for mdev: %s\n",
|
2016-12-30 23:13:44 +08:00
|
|
|
dev_name(mdev_dev(mdev)));
|
2017-01-06 15:16:20 +08:00
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
out:
|
|
|
|
return ret;
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_remove(struct mdev_device *mdev)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
|
|
|
|
|
|
|
|
if (handle_valid(vgpu->handle))
|
|
|
|
return -EBUSY;
|
|
|
|
|
|
|
|
intel_gvt_ops->vgpu_destroy(vgpu);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_iommu_notifier(struct notifier_block *nb,
|
|
|
|
unsigned long action, void *data)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = container_of(nb,
|
|
|
|
struct intel_vgpu,
|
|
|
|
vdev.iommu_notifier);
|
|
|
|
|
|
|
|
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
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
mutex_lock(&vgpu->vdev.cache_lock);
|
|
|
|
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-03-01 15:49:59 +08:00
|
|
|
gvt_dma_unmap_page(vgpu, entry->gfn, entry->dma_addr);
|
|
|
|
__gvt_cache_remove_entry(vgpu, entry);
|
|
|
|
}
|
|
|
|
mutex_unlock(&vgpu->vdev.cache_lock);
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return NOTIFY_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_group_notifier(struct notifier_block *nb,
|
|
|
|
unsigned long action, void *data)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = container_of(nb,
|
|
|
|
struct intel_vgpu,
|
|
|
|
vdev.group_notifier);
|
|
|
|
|
|
|
|
/* the only action we care about */
|
|
|
|
if (action == VFIO_GROUP_NOTIFY_SET_KVM) {
|
|
|
|
vgpu->vdev.kvm = data;
|
|
|
|
|
|
|
|
if (!data)
|
|
|
|
schedule_work(&vgpu->vdev.release_work);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NOTIFY_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_open(struct mdev_device *mdev)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
|
|
|
|
unsigned long events;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
vgpu->vdev.iommu_notifier.notifier_call = intel_vgpu_iommu_notifier;
|
|
|
|
vgpu->vdev.group_notifier.notifier_call = intel_vgpu_group_notifier;
|
|
|
|
|
|
|
|
events = VFIO_IOMMU_NOTIFY_DMA_UNMAP;
|
2016-12-30 23:13:44 +08:00
|
|
|
ret = vfio_register_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY, &events,
|
2016-12-08 11:00:36 +08:00
|
|
|
&vgpu->vdev.iommu_notifier);
|
|
|
|
if (ret != 0) {
|
2017-03-10 17:26:53 +08:00
|
|
|
gvt_vgpu_err("vfio_register_notifier for iommu failed: %d\n",
|
|
|
|
ret);
|
2016-12-08 11:00:36 +08:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
events = VFIO_GROUP_NOTIFY_SET_KVM;
|
2016-12-30 23:13:44 +08:00
|
|
|
ret = vfio_register_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY, &events,
|
2016-12-08 11:00:36 +08:00
|
|
|
&vgpu->vdev.group_notifier);
|
|
|
|
if (ret != 0) {
|
2017-03-10 17:26:53 +08:00
|
|
|
gvt_vgpu_err("vfio_register_notifier for group failed: %d\n",
|
|
|
|
ret);
|
2016-12-08 11:00:36 +08:00
|
|
|
goto undo_iommu;
|
|
|
|
}
|
|
|
|
|
2016-12-16 10:51:06 +08:00
|
|
|
ret = kvmgt_guest_init(mdev);
|
|
|
|
if (ret)
|
|
|
|
goto undo_group;
|
|
|
|
|
2017-03-30 01:48:39 +08:00
|
|
|
intel_gvt_ops->vgpu_activate(vgpu);
|
|
|
|
|
2016-12-16 10:51:06 +08:00
|
|
|
atomic_set(&vgpu->vdev.released, 0);
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
undo_group:
|
2017-01-07 03:19:03 +08:00
|
|
|
vfio_unregister_notifier(mdev_dev(mdev), VFIO_GROUP_NOTIFY,
|
2016-12-16 10:51:06 +08:00
|
|
|
&vgpu->vdev.group_notifier);
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
undo_iommu:
|
2016-12-30 23:13:44 +08:00
|
|
|
vfio_unregister_notifier(mdev_dev(mdev), VFIO_IOMMU_NOTIFY,
|
2016-12-08 11:00:36 +08:00
|
|
|
&vgpu->vdev.iommu_notifier);
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __intel_vgpu_release(struct intel_vgpu *vgpu)
|
|
|
|
{
|
|
|
|
struct kvmgt_guest_info *info;
|
2016-12-16 10:51:06 +08:00
|
|
|
int ret;
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
if (!handle_valid(vgpu->handle))
|
|
|
|
return;
|
|
|
|
|
2016-12-16 10:51:06 +08:00
|
|
|
if (atomic_cmpxchg(&vgpu->vdev.released, 0, 1))
|
|
|
|
return;
|
|
|
|
|
2017-03-30 01:48:39 +08:00
|
|
|
intel_gvt_ops->vgpu_deactivate(vgpu);
|
|
|
|
|
2017-01-07 03:19:03 +08:00
|
|
|
ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_IOMMU_NOTIFY,
|
2016-12-08 11:00:36 +08:00
|
|
|
&vgpu->vdev.iommu_notifier);
|
2016-12-16 10:51:06 +08:00
|
|
|
WARN(ret, "vfio_unregister_notifier for iommu failed: %d\n", ret);
|
|
|
|
|
2017-01-07 03:19:03 +08:00
|
|
|
ret = vfio_unregister_notifier(mdev_dev(vgpu->vdev.mdev), VFIO_GROUP_NOTIFY,
|
2016-12-08 11:00:36 +08:00
|
|
|
&vgpu->vdev.group_notifier);
|
2016-12-16 10:51:06 +08:00
|
|
|
WARN(ret, "vfio_unregister_notifier for group failed: %d\n", ret);
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
info = (struct kvmgt_guest_info *)vgpu->handle;
|
|
|
|
kvmgt_guest_exit(info);
|
2016-12-16 10:51:06 +08:00
|
|
|
|
|
|
|
vgpu->vdev.kvm = NULL;
|
2016-12-08 11:00:36 +08:00
|
|
|
vgpu->handle = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_vgpu_release(struct mdev_device *mdev)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
|
|
|
|
|
|
|
|
__intel_vgpu_release(vgpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void intel_vgpu_release_work(struct work_struct *work)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = container_of(work, struct intel_vgpu,
|
|
|
|
vdev.release_work);
|
2016-12-16 10:51:07 +08:00
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
__intel_vgpu_release(vgpu);
|
|
|
|
}
|
|
|
|
|
2017-08-15 13:14:04 +08:00
|
|
|
static uint64_t 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;
|
|
|
|
}
|
|
|
|
|
2017-08-15 13:14:04 +08:00
|
|
|
static int intel_vgpu_bar_rw(struct intel_vgpu *vgpu, int bar, uint64_t off,
|
|
|
|
void *buf, unsigned int count, bool is_write)
|
|
|
|
{
|
|
|
|
uint64_t bar_start = intel_vgpu_get_bar_addr(vgpu, bar);
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (is_write)
|
|
|
|
ret = intel_gvt_ops->emulate_mmio_write(vgpu,
|
|
|
|
bar_start + off, buf, count);
|
|
|
|
else
|
|
|
|
ret = intel_gvt_ops->emulate_mmio_read(vgpu,
|
|
|
|
bar_start + off, buf, count);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2018-01-30 13:51:31 +08:00
|
|
|
static inline bool intel_vgpu_in_aperture(struct intel_vgpu *vgpu, uint64_t off)
|
|
|
|
{
|
|
|
|
return off >= vgpu_aperture_offset(vgpu) &&
|
|
|
|
off < vgpu_aperture_offset(vgpu) + vgpu_aperture_sz(vgpu);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_aperture_rw(struct intel_vgpu *vgpu, uint64_t off,
|
|
|
|
void *buf, unsigned long count, bool is_write)
|
|
|
|
{
|
|
|
|
void *aperture_va;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
aperture_va = io_mapping_map_wc(&vgpu->gvt->dev_priv->ggtt.iomap,
|
|
|
|
ALIGN_DOWN(off, PAGE_SIZE),
|
|
|
|
count + offset_in_page(off));
|
|
|
|
if (!aperture_va)
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
if (is_write)
|
|
|
|
memcpy(aperture_va + offset_in_page(off), buf, count);
|
|
|
|
else
|
|
|
|
memcpy(buf, aperture_va + offset_in_page(off), count);
|
|
|
|
|
|
|
|
io_mapping_unmap(aperture_va);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
static ssize_t intel_vgpu_rw(struct mdev_device *mdev, char *buf,
|
|
|
|
size_t count, loff_t *ppos, bool is_write)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
|
|
|
|
unsigned int index = VFIO_PCI_OFFSET_TO_INDEX(*ppos);
|
|
|
|
uint64_t pos = *ppos & VFIO_PCI_OFFSET_MASK;
|
|
|
|
int ret = -EINVAL;
|
|
|
|
|
|
|
|
|
2017-11-20 15:31:16 +08:00
|
|
|
if (index >= VFIO_PCI_NUM_REGIONS + vgpu->vdev.num_regions) {
|
2017-03-10 17:26:53 +08: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)
|
|
|
|
ret = intel_gvt_ops->emulate_cfg_write(vgpu, pos,
|
|
|
|
buf, count);
|
|
|
|
else
|
|
|
|
ret = intel_gvt_ops->emulate_cfg_read(vgpu, pos,
|
|
|
|
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:
|
2017-11-20 15:31:16 +08:00
|
|
|
if (index >= VFIO_PCI_NUM_REGIONS + vgpu->vdev.num_regions)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
index -= VFIO_PCI_NUM_REGIONS;
|
|
|
|
return vgpu->vdev.region[index].ops->rw(vgpu, buf, count,
|
|
|
|
ppos, is_write);
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret == 0 ? count : ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t intel_vgpu_read(struct mdev_device *mdev, char __user *buf,
|
|
|
|
size_t count, loff_t *ppos)
|
|
|
|
{
|
|
|
|
unsigned int done = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
size_t filled;
|
|
|
|
|
|
|
|
if (count >= 4 && !(*ppos % 4)) {
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
|
|
|
|
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;
|
|
|
|
|
|
|
|
ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
|
|
|
|
ppos, false);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
if (copy_to_user(buf, &val, sizeof(val)))
|
|
|
|
goto read_err;
|
|
|
|
|
|
|
|
filled = 2;
|
|
|
|
} else {
|
|
|
|
u8 val;
|
|
|
|
|
|
|
|
ret = intel_vgpu_rw(mdev, &val, sizeof(val), ppos,
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ssize_t intel_vgpu_write(struct mdev_device *mdev,
|
|
|
|
const char __user *buf,
|
|
|
|
size_t count, loff_t *ppos)
|
|
|
|
{
|
|
|
|
unsigned int done = 0;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
while (count) {
|
|
|
|
size_t filled;
|
|
|
|
|
|
|
|
if (count >= 4 && !(*ppos % 4)) {
|
|
|
|
u32 val;
|
|
|
|
|
|
|
|
if (copy_from_user(&val, buf, sizeof(val)))
|
|
|
|
goto write_err;
|
|
|
|
|
|
|
|
ret = intel_vgpu_rw(mdev, (char *)&val, sizeof(val),
|
|
|
|
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;
|
|
|
|
|
|
|
|
ret = intel_vgpu_rw(mdev, (char *)&val,
|
|
|
|
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;
|
|
|
|
|
|
|
|
ret = intel_vgpu_rw(mdev, &val, sizeof(val),
|
|
|
|
ppos, true);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto write_err;
|
|
|
|
|
|
|
|
filled = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
count -= filled;
|
|
|
|
done += filled;
|
|
|
|
*ppos += filled;
|
|
|
|
buf += filled;
|
|
|
|
}
|
|
|
|
|
|
|
|
return done;
|
|
|
|
write_err:
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_mmap(struct mdev_device *mdev, struct vm_area_struct *vma)
|
|
|
|
{
|
|
|
|
unsigned int index;
|
|
|
|
u64 virtaddr;
|
|
|
|
unsigned long req_size, pgoff = 0;
|
|
|
|
pgprot_t pg_prot;
|
|
|
|
struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
|
|
|
|
|
|
|
|
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;
|
|
|
|
pgoff = vgpu_aperture_pa_base(vgpu) >> PAGE_SHIFT;
|
|
|
|
|
|
|
|
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,
|
|
|
|
unsigned int count, uint32_t flags,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_set_intx_unmask(struct intel_vgpu *vgpu,
|
|
|
|
unsigned int index, unsigned int start,
|
|
|
|
unsigned int count, uint32_t flags, void *data)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_set_intx_trigger(struct intel_vgpu *vgpu,
|
|
|
|
unsigned int index, unsigned int start, unsigned int count,
|
|
|
|
uint32_t flags, void *data)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_set_msi_trigger(struct intel_vgpu *vgpu,
|
|
|
|
unsigned int index, unsigned int start, unsigned int count,
|
|
|
|
uint32_t flags, void *data)
|
|
|
|
{
|
|
|
|
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 17:26:53 +08:00
|
|
|
gvt_vgpu_err("eventfd_ctx_fdget failed\n");
|
2016-12-08 11:00:36 +08:00
|
|
|
return PTR_ERR(trigger);
|
|
|
|
}
|
|
|
|
vgpu->vdev.msi_trigger = trigger;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int intel_vgpu_set_irqs(struct intel_vgpu *vgpu, uint32_t flags,
|
|
|
|
unsigned int index, unsigned int start, unsigned int count,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
int (*func)(struct intel_vgpu *vgpu, unsigned int index,
|
|
|
|
unsigned int start, unsigned int count, uint32_t flags,
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
static long intel_vgpu_ioctl(struct mdev_device *mdev, unsigned int cmd,
|
|
|
|
unsigned long arg)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *vgpu = mdev_get_drvdata(mdev);
|
|
|
|
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 +
|
|
|
|
vgpu->vdev.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 };
|
|
|
|
int i, ret;
|
|
|
|
struct vfio_region_info_cap_sparse_mmap *sparse = NULL;
|
|
|
|
size_t size;
|
|
|
|
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);
|
|
|
|
|
|
|
|
size = sizeof(*sparse) +
|
|
|
|
(nr_areas * sizeof(*sparse->areas));
|
|
|
|
sparse = kzalloc(size, GFP_KERNEL);
|
|
|
|
if (!sparse)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
2017-12-13 03:59:39 +08: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-13 03:59:39 +08: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 +
|
|
|
|
vgpu->vdev.num_regions)
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
i = info.index - VFIO_PCI_NUM_REGIONS;
|
|
|
|
|
|
|
|
info.offset =
|
|
|
|
VFIO_PCI_INDEX_TO_OFFSET(info.index);
|
|
|
|
info.size = vgpu->vdev.region[i].size;
|
|
|
|
info.flags = vgpu->vdev.region[i].flags;
|
|
|
|
|
|
|
|
cap_type.type = vgpu->vdev.region[i].type;
|
|
|
|
cap_type.subtype = vgpu->vdev.region[i].subtype;
|
|
|
|
|
|
|
|
ret = vfio_info_add_capability(&caps,
|
2017-12-13 03:59:39 +08: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,
|
2017-12-13 03:59:39 +08:00
|
|
|
&sparse->header, sizeof(*sparse) +
|
|
|
|
(sparse->nr_areas *
|
|
|
|
sizeof(*sparse->areas)));
|
2016-12-08 11:00:36 +08:00
|
|
|
kfree(sparse);
|
|
|
|
if (ret)
|
|
|
|
return ret;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
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);
|
|
|
|
return -EFAULT;
|
|
|
|
}
|
|
|
|
info.cap_offset = sizeof(info);
|
|
|
|
}
|
|
|
|
|
|
|
|
kfree(caps.buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
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 17:26:53 +08: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) {
|
|
|
|
intel_gvt_ops->vgpu_reset(vgpu);
|
|
|
|
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;
|
|
|
|
|
|
|
|
ret = intel_gvt_ops->vgpu_query_plane(vgpu, &dmabuf);
|
|
|
|
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;
|
|
|
|
__s32 dmabuf_fd;
|
|
|
|
|
|
|
|
if (get_user(dmabuf_id, (__u32 __user *)arg))
|
|
|
|
return -EFAULT;
|
|
|
|
|
|
|
|
dmabuf_fd = intel_gvt_ops->vgpu_get_dmabuf(vgpu, dmabuf_id);
|
|
|
|
return dmabuf_fd;
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2017-03-16 18:06:39 +08:00
|
|
|
static ssize_t
|
|
|
|
vgpu_id_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct mdev_device *mdev = mdev_from_dev(dev);
|
|
|
|
|
|
|
|
if (mdev) {
|
|
|
|
struct intel_vgpu *vgpu = (struct intel_vgpu *)
|
|
|
|
mdev_get_drvdata(mdev);
|
|
|
|
return sprintf(buf, "%d\n", vgpu->id);
|
|
|
|
}
|
|
|
|
return sprintf(buf, "\n");
|
|
|
|
}
|
|
|
|
|
2017-08-01 13:09:47 +08:00
|
|
|
static ssize_t
|
|
|
|
hw_id_show(struct device *dev, struct device_attribute *attr,
|
|
|
|
char *buf)
|
|
|
|
{
|
|
|
|
struct mdev_device *mdev = mdev_from_dev(dev);
|
|
|
|
|
|
|
|
if (mdev) {
|
|
|
|
struct intel_vgpu *vgpu = (struct intel_vgpu *)
|
|
|
|
mdev_get_drvdata(mdev);
|
|
|
|
return sprintf(buf, "%u\n",
|
2017-09-10 21:15:18 +08:00
|
|
|
vgpu->submission.shadow_ctx->hw_id);
|
2017-08-01 13:09:47 +08:00
|
|
|
}
|
|
|
|
return sprintf(buf, "\n");
|
|
|
|
}
|
|
|
|
|
2017-03-16 18:06:39 +08:00
|
|
|
static DEVICE_ATTR_RO(vgpu_id);
|
2017-08-01 13:09:47 +08:00
|
|
|
static DEVICE_ATTR_RO(hw_id);
|
2017-03-16 18:06:39 +08:00
|
|
|
|
|
|
|
static struct attribute *intel_vgpu_attrs[] = {
|
|
|
|
&dev_attr_vgpu_id.attr,
|
2017-08-01 13:09:47 +08:00
|
|
|
&dev_attr_hw_id.attr,
|
2017-03-16 18:06:39 +08:00
|
|
|
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,
|
|
|
|
};
|
|
|
|
|
2017-09-28 11:03:03 +08:00
|
|
|
static struct mdev_parent_ops intel_vgpu_ops = {
|
2017-03-16 18:06:39 +08:00
|
|
|
.mdev_attr_groups = intel_vgpu_groups,
|
2016-12-08 11:00:36 +08:00
|
|
|
.create = intel_vgpu_create,
|
|
|
|
.remove = intel_vgpu_remove,
|
|
|
|
|
|
|
|
.open = intel_vgpu_open,
|
|
|
|
.release = intel_vgpu_release,
|
|
|
|
|
|
|
|
.read = intel_vgpu_read,
|
|
|
|
.write = intel_vgpu_write,
|
|
|
|
.mmap = intel_vgpu_mmap,
|
|
|
|
.ioctl = intel_vgpu_ioctl,
|
|
|
|
};
|
|
|
|
|
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 kvmgt_host_init(struct device *dev, void *gvt, const void *ops)
|
|
|
|
{
|
2017-09-28 11:03:03 +08:00
|
|
|
struct attribute **kvm_type_attrs;
|
|
|
|
struct attribute_group **kvm_vgpu_type_groups;
|
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
|
|
|
|
|
|
|
intel_gvt_ops = ops;
|
2017-09-28 11:03:03 +08:00
|
|
|
if (!intel_gvt_ops->get_gvt_attrs(&kvm_type_attrs,
|
|
|
|
&kvm_vgpu_type_groups))
|
|
|
|
return -EFAULT;
|
|
|
|
intel_vgpu_ops.supported_type_groups = kvm_vgpu_type_groups;
|
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
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
return mdev_register_device(dev, &intel_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
|
|
|
}
|
|
|
|
|
|
|
|
static void kvmgt_host_exit(struct device *dev, void *gvt)
|
|
|
|
{
|
2016-12-08 11:00:36 +08:00
|
|
|
mdev_unregister_device(dev);
|
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-01-30 19:19:51 +08:00
|
|
|
static int kvmgt_page_track_add(unsigned long handle, 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
|
|
|
{
|
2016-12-08 11:00:36 +08:00
|
|
|
struct kvmgt_guest_info *info;
|
|
|
|
struct kvm *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;
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
if (!handle_valid(handle))
|
|
|
|
return -ESRCH;
|
|
|
|
|
|
|
|
info = (struct kvmgt_guest_info *)handle;
|
|
|
|
kvm = info->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
|
|
|
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
|
|
|
|
|
|
|
spin_lock(&kvm->mmu_lock);
|
|
|
|
|
|
|
|
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:
|
|
|
|
spin_unlock(&kvm->mmu_lock);
|
|
|
|
srcu_read_unlock(&kvm->srcu, idx);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-01-30 19:19:51 +08:00
|
|
|
static int kvmgt_page_track_remove(unsigned long handle, 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
|
|
|
{
|
2016-12-08 11:00:36 +08:00
|
|
|
struct kvmgt_guest_info *info;
|
|
|
|
struct kvm *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;
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
if (!handle_valid(handle))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
info = (struct kvmgt_guest_info *)handle;
|
|
|
|
kvm = info->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
|
|
|
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
|
|
|
|
|
|
|
spin_lock(&kvm->mmu_lock);
|
|
|
|
|
|
|
|
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:
|
|
|
|
spin_unlock(&kvm->mmu_lock);
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
struct kvmgt_guest_info *info = container_of(node,
|
|
|
|
struct kvmgt_guest_info, track_node);
|
|
|
|
|
|
|
|
if (kvmgt_gfn_is_write_protected(info, gpa_to_gfn(gpa)))
|
2017-12-18 11:58:46 +08:00
|
|
|
intel_gvt_ops->write_protect_handler(info->vgpu, gpa,
|
|
|
|
(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;
|
|
|
|
struct kvmgt_guest_info *info = container_of(node,
|
|
|
|
struct kvmgt_guest_info, track_node);
|
|
|
|
|
|
|
|
spin_lock(&kvm->mmu_lock);
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
spin_unlock(&kvm->mmu_lock);
|
|
|
|
}
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
static bool __kvmgt_vgpu_exist(struct intel_vgpu *vgpu, struct kvm *kvm)
|
|
|
|
{
|
|
|
|
struct intel_vgpu *itr;
|
|
|
|
struct kvmgt_guest_info *info;
|
|
|
|
int id;
|
|
|
|
bool ret = false;
|
|
|
|
|
|
|
|
mutex_lock(&vgpu->gvt->lock);
|
|
|
|
for_each_active_vgpu(vgpu->gvt, itr, id) {
|
|
|
|
if (!handle_valid(itr->handle))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
info = (struct kvmgt_guest_info *)itr->handle;
|
|
|
|
if (kvm && kvm == info->kvm) {
|
|
|
|
ret = true;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
out:
|
|
|
|
mutex_unlock(&vgpu->gvt->lock);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvmgt_guest_init(struct mdev_device *mdev)
|
|
|
|
{
|
|
|
|
struct kvmgt_guest_info *info;
|
|
|
|
struct intel_vgpu *vgpu;
|
|
|
|
struct kvm *kvm;
|
|
|
|
|
|
|
|
vgpu = mdev_get_drvdata(mdev);
|
|
|
|
if (handle_valid(vgpu->handle))
|
|
|
|
return -EEXIST;
|
|
|
|
|
|
|
|
kvm = vgpu->vdev.kvm;
|
|
|
|
if (!kvm || kvm->mm != current->mm) {
|
2017-03-10 17:26:53 +08:00
|
|
|
gvt_vgpu_err("KVM is required to use Intel vGPU\n");
|
2016-12-08 11:00:36 +08:00
|
|
|
return -ESRCH;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (__kvmgt_vgpu_exist(vgpu, kvm))
|
|
|
|
return -EEXIST;
|
|
|
|
|
|
|
|
info = vzalloc(sizeof(struct kvmgt_guest_info));
|
|
|
|
if (!info)
|
|
|
|
return -ENOMEM;
|
|
|
|
|
|
|
|
vgpu->handle = (unsigned long)info;
|
|
|
|
info->vgpu = vgpu;
|
|
|
|
info->kvm = kvm;
|
2017-03-20 10:38:40 +08:00
|
|
|
kvm_get_kvm(info->kvm);
|
2016-12-08 11:00:36 +08:00
|
|
|
|
|
|
|
kvmgt_protect_table_init(info);
|
|
|
|
gvt_cache_init(vgpu);
|
|
|
|
|
2017-11-23 16:26:36 +08:00
|
|
|
mutex_init(&vgpu->dmabuf_lock);
|
|
|
|
init_completion(&vgpu->vblank_done);
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
info->track_node.track_write = kvmgt_page_track_write;
|
|
|
|
info->track_node.track_flush_slot = kvmgt_page_track_flush_slot;
|
|
|
|
kvm_page_track_register_notifier(kvm, &info->track_node);
|
|
|
|
|
2018-03-05 15:30:34 +08:00
|
|
|
info->debugfs_cache_entries = debugfs_create_ulong(
|
|
|
|
"kvmgt_nr_cache_entries",
|
|
|
|
0444, vgpu->debugfs,
|
|
|
|
&vgpu->vdev.nr_cache_entries);
|
|
|
|
if (!info->debugfs_cache_entries)
|
|
|
|
gvt_vgpu_err("Cannot create kvmgt debugfs entry\n");
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool kvmgt_guest_exit(struct kvmgt_guest_info *info)
|
|
|
|
{
|
2018-03-05 15:30:34 +08:00
|
|
|
debugfs_remove(info->debugfs_cache_entries);
|
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
kvm_page_track_unregister_notifier(info->kvm, &info->track_node);
|
2017-03-20 10:38:40 +08:00
|
|
|
kvm_put_kvm(info->kvm);
|
2016-12-08 11:00:36 +08:00
|
|
|
kvmgt_protect_table_destroy(info);
|
2016-12-16 10:51:07 +08:00
|
|
|
gvt_cache_destroy(info->vgpu);
|
2016-12-08 11:00:36 +08:00
|
|
|
vfree(info);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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 kvmgt_attach_vgpu(void *vgpu, unsigned long *handle)
|
|
|
|
{
|
|
|
|
/* nothing to do here */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void kvmgt_detach_vgpu(unsigned long handle)
|
|
|
|
{
|
|
|
|
/* nothing to do here */
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvmgt_inject_msi(unsigned long handle, u32 addr, u16 data)
|
|
|
|
{
|
2016-12-08 11:00:36 +08:00
|
|
|
struct kvmgt_guest_info *info;
|
|
|
|
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
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
if (!handle_valid(handle))
|
|
|
|
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
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
info = (struct kvmgt_guest_info *)handle;
|
|
|
|
vgpu = info->vgpu;
|
|
|
|
|
|
|
|
if (eventfd_signal(vgpu->vdev.msi_trigger, 1) == 1)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return -EFAULT;
|
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 unsigned long kvmgt_gfn_to_pfn(unsigned long handle, unsigned long gfn)
|
|
|
|
{
|
2016-12-08 11:00:36 +08:00
|
|
|
struct kvmgt_guest_info *info;
|
2018-03-01 15:49:59 +08:00
|
|
|
kvm_pfn_t pfn;
|
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
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
if (!handle_valid(handle))
|
|
|
|
return INTEL_GVT_INVALID_ADDR;
|
|
|
|
|
|
|
|
info = (struct kvmgt_guest_info *)handle;
|
2018-03-01 15:49:59 +08:00
|
|
|
|
|
|
|
pfn = gfn_to_pfn(info->kvm, gfn);
|
|
|
|
if (is_error_noslot_pfn(pfn))
|
2017-02-14 17:15:54 +08:00
|
|
|
return INTEL_GVT_INVALID_ADDR;
|
2018-03-01 15:49:59 +08:00
|
|
|
|
|
|
|
return pfn;
|
|
|
|
}
|
|
|
|
|
|
|
|
int kvmgt_dma_map_guest_page(unsigned long handle, unsigned long gfn,
|
|
|
|
dma_addr_t *dma_addr)
|
|
|
|
{
|
|
|
|
struct kvmgt_guest_info *info;
|
|
|
|
struct intel_vgpu *vgpu;
|
|
|
|
struct gvt_dma *entry;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (!handle_valid(handle))
|
|
|
|
return -EINVAL;
|
|
|
|
|
|
|
|
info = (struct kvmgt_guest_info *)handle;
|
|
|
|
vgpu = info->vgpu;
|
|
|
|
|
|
|
|
mutex_lock(&info->vgpu->vdev.cache_lock);
|
|
|
|
|
|
|
|
entry = __gvt_cache_find_gfn(info->vgpu, gfn);
|
|
|
|
if (!entry) {
|
|
|
|
ret = gvt_dma_map_page(vgpu, gfn, dma_addr);
|
|
|
|
if (ret) {
|
|
|
|
mutex_unlock(&info->vgpu->vdev.cache_lock);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
__gvt_cache_add(info->vgpu, gfn, *dma_addr);
|
|
|
|
} 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
|
|
|
|
2018-03-01 15:49:59 +08:00
|
|
|
mutex_unlock(&info->vgpu->vdev.cache_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __gvt_dma_release(struct kref *ref)
|
|
|
|
{
|
|
|
|
struct gvt_dma *entry = container_of(ref, typeof(*entry), ref);
|
|
|
|
|
|
|
|
gvt_dma_unmap_page(entry->vgpu, entry->gfn, entry->dma_addr);
|
|
|
|
__gvt_cache_remove_entry(entry->vgpu, entry);
|
|
|
|
}
|
|
|
|
|
|
|
|
void kvmgt_dma_unmap_guest_page(unsigned long handle, dma_addr_t dma_addr)
|
|
|
|
{
|
|
|
|
struct kvmgt_guest_info *info;
|
|
|
|
struct gvt_dma *entry;
|
|
|
|
|
|
|
|
if (!handle_valid(handle))
|
|
|
|
return;
|
|
|
|
|
|
|
|
info = (struct kvmgt_guest_info *)handle;
|
|
|
|
|
|
|
|
mutex_lock(&info->vgpu->vdev.cache_lock);
|
|
|
|
entry = __gvt_cache_find_dma_addr(info->vgpu, dma_addr);
|
|
|
|
if (entry)
|
|
|
|
kref_put(&entry->ref, __gvt_dma_release);
|
|
|
|
mutex_unlock(&info->vgpu->vdev.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
|
|
|
}
|
|
|
|
|
|
|
|
static int kvmgt_rw_gpa(unsigned long handle, unsigned long gpa,
|
|
|
|
void *buf, unsigned long len, bool write)
|
|
|
|
{
|
2016-12-08 11:00:35 +08:00
|
|
|
struct kvmgt_guest_info *info;
|
|
|
|
struct kvm *kvm;
|
2017-03-16 09:45:09 +08:00
|
|
|
int idx, ret;
|
2016-12-08 11:00:35 +08:00
|
|
|
bool kthread = current->mm == 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
|
|
|
|
2016-12-08 11:00:36 +08:00
|
|
|
if (!handle_valid(handle))
|
|
|
|
return -ESRCH;
|
|
|
|
|
2016-12-08 11:00:35 +08:00
|
|
|
info = (struct kvmgt_guest_info *)handle;
|
|
|
|
kvm = info->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
|
|
|
|
2016-12-08 11:00:35 +08:00
|
|
|
if (kthread)
|
|
|
|
use_mm(kvm->mm);
|
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
|
|
|
|
2017-03-16 09:45:09 +08:00
|
|
|
idx = srcu_read_lock(&kvm->srcu);
|
2016-12-08 11:00:35 +08:00
|
|
|
ret = write ? kvm_write_guest(kvm, gpa, buf, len) :
|
|
|
|
kvm_read_guest(kvm, gpa, buf, len);
|
2017-03-16 09:45:09 +08:00
|
|
|
srcu_read_unlock(&kvm->srcu, idx);
|
2016-12-08 11:00:35 +08:00
|
|
|
|
|
|
|
if (kthread)
|
|
|
|
unuse_mm(kvm->mm);
|
|
|
|
|
|
|
|
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 int kvmgt_read_gpa(unsigned long handle, unsigned long gpa,
|
|
|
|
void *buf, unsigned long len)
|
|
|
|
{
|
|
|
|
return kvmgt_rw_gpa(handle, gpa, buf, len, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int kvmgt_write_gpa(unsigned long handle, unsigned long gpa,
|
|
|
|
void *buf, unsigned long len)
|
|
|
|
{
|
|
|
|
return kvmgt_rw_gpa(handle, gpa, buf, len, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long kvmgt_virt_to_pfn(void *addr)
|
|
|
|
{
|
|
|
|
return PFN_DOWN(__pa(addr));
|
|
|
|
}
|
|
|
|
|
2017-12-22 18:06:31 +08:00
|
|
|
static bool kvmgt_is_valid_gfn(unsigned long handle, unsigned long gfn)
|
|
|
|
{
|
|
|
|
struct kvmgt_guest_info *info;
|
|
|
|
struct kvm *kvm;
|
|
|
|
|
|
|
|
if (!handle_valid(handle))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
info = (struct kvmgt_guest_info *)handle;
|
|
|
|
kvm = info->kvm;
|
|
|
|
|
|
|
|
return kvm_is_visible_gfn(kvm, 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 intel_gvt_mpt kvmgt_mpt = {
|
|
|
|
.host_init = kvmgt_host_init,
|
|
|
|
.host_exit = kvmgt_host_exit,
|
|
|
|
.attach_vgpu = kvmgt_attach_vgpu,
|
|
|
|
.detach_vgpu = kvmgt_detach_vgpu,
|
|
|
|
.inject_msi = kvmgt_inject_msi,
|
|
|
|
.from_virt_to_mfn = kvmgt_virt_to_pfn,
|
2018-01-30 19:19:51 +08:00
|
|
|
.enable_page_track = kvmgt_page_track_add,
|
|
|
|
.disable_page_track = kvmgt_page_track_remove,
|
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
|
|
|
.read_gpa = kvmgt_read_gpa,
|
|
|
|
.write_gpa = kvmgt_write_gpa,
|
|
|
|
.gfn_to_mfn = kvmgt_gfn_to_pfn,
|
2018-03-01 15:49:59 +08:00
|
|
|
.dma_map_guest_page = kvmgt_dma_map_guest_page,
|
|
|
|
.dma_unmap_guest_page = kvmgt_dma_unmap_guest_page,
|
2017-11-20 15:31:16 +08:00
|
|
|
.set_opregion = kvmgt_set_opregion,
|
2017-11-23 16:26:36 +08:00
|
|
|
.get_vfio_device = kvmgt_get_vfio_device,
|
|
|
|
.put_vfio_device = kvmgt_put_vfio_device,
|
2017-12-22 18:06:31 +08:00
|
|
|
.is_valid_gfn = kvmgt_is_valid_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
|
|
|
};
|
|
|
|
EXPORT_SYMBOL_GPL(kvmgt_mpt);
|
|
|
|
|
|
|
|
static int __init kvmgt_init(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __exit kvmgt_exit(void)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
module_init(kvmgt_init);
|
|
|
|
module_exit(kvmgt_exit);
|
|
|
|
|
|
|
|
MODULE_LICENSE("GPL and additional rights");
|
|
|
|
MODULE_AUTHOR("Intel Corporation");
|