Commit 9bdb0734 authored by Zhenyu Wang's avatar Zhenyu Wang

drm/i915/gvt: Change KVMGT as self load module

This trys to make 'kvmgt' module as self loadable instead of loading
by i915/gvt device model. So hypervisor specific module could be
stand-alone, e.g only after loading hypervisor specific module, GVT
feature could be enabled via specific hypervisor interface, e.g VFIO/mdev.

So this trys to use hypervisor module register/unregister interface
for that. Hypervisor module needs to take care of module reference
itself when working for hypervisor interface, e.g for VFIO/mdev,
hypervisor module would reference counting mdev when open and release.

This makes 'kvmgt' module really split from GVT device model. User
needs to load 'kvmgt' to enable VFIO/mdev interface.

v6:
- remove unused variable

v5:
- put module reference in register error path

v4:
- fix checkpatch warning

v3:
- Fix module reference handling for device open and release. Unused
  mdev devices would be cleaned up in device unregister when module unload.

v2:
- Fix kvmgt order after i915 for built-in case

Cc: "Yuan, Hang" <hang.yuan@intel.com>
Cc: Alex Williamson <alex.williamson@redhat.com>
Cc: "He, Min" <min.he@intel.com>
Reviewed-by: default avatarYuan, Hang <hang.yuan@intel.com>
Acked-by: default avatarJoonas Lahtinen <joonas.lahtinen@linux.intel.com>
Signed-off-by: default avatarZhenyu Wang <zhenyuw@linux.intel.com>
parent a2b8419a
......@@ -198,3 +198,4 @@ endif
i915-y += intel_lpe_audio.o
obj-$(CONFIG_DRM_I915) += i915.o
obj-$(CONFIG_DRM_I915_GVT_KVMGT) += gvt/kvmgt.o
......@@ -7,4 +7,3 @@ GVT_SOURCE := gvt.o aperture_gm.o handlers.o vgpu.o trace_points.o firmware.o \
ccflags-y += -I$(src) -I$(src)/$(GVT_DIR)
i915-y += $(addprefix $(GVT_DIR)/, $(GVT_SOURCE))
obj-$(CONFIG_DRM_I915_GVT_KVMGT) += $(GVT_DIR)/kvmgt.o
......@@ -187,52 +187,6 @@ static const struct intel_gvt_ops intel_gvt_ops = {
.write_protect_handler = intel_vgpu_page_track_handler,
};
/**
* intel_gvt_init_host - Load MPT modules and detect if we're running in host
*
* This function is called at the driver loading stage. If failed to find a
* loadable MPT module or detect currently we're running in a VM, then GVT-g
* will be disabled
*
* Returns:
* Zero on success, negative error code if failed.
*
*/
int intel_gvt_init_host(void)
{
if (intel_gvt_host.initialized)
return 0;
/* Xen DOM U */
if (xen_domain() && !xen_initial_domain())
return -ENODEV;
/* Try to load MPT modules for hypervisors */
if (xen_initial_domain()) {
/* In Xen dom0 */
intel_gvt_host.mpt = try_then_request_module(
symbol_get(xengt_mpt), "xengt");
intel_gvt_host.hypervisor_type = INTEL_GVT_HYPERVISOR_XEN;
} else {
#if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT)
/* not in Xen. Try KVMGT */
intel_gvt_host.mpt = try_then_request_module(
symbol_get(kvmgt_mpt), "kvmgt");
intel_gvt_host.hypervisor_type = INTEL_GVT_HYPERVISOR_KVM;
#endif
}
/* Fail to load MPT modules - bail out */
if (!intel_gvt_host.mpt)
return -EINVAL;
gvt_dbg_core("Running with hypervisor %s in host mode\n",
supported_hypervisors[intel_gvt_host.hypervisor_type]);
intel_gvt_host.initialized = true;
return 0;
}
static void init_device_info(struct intel_gvt *gvt)
{
struct intel_gvt_device_info *info = &gvt->device_info;
......@@ -316,7 +270,6 @@ void intel_gvt_clean_device(struct drm_i915_private *dev_priv)
return;
intel_gvt_destroy_idle_vgpu(gvt->idle_vgpu);
intel_gvt_hypervisor_host_exit(&dev_priv->drm.pdev->dev);
intel_gvt_cleanup_vgpu_type_groups(gvt);
intel_gvt_clean_vgpu_types(gvt);
......@@ -352,13 +305,6 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
struct intel_vgpu *vgpu;
int ret;
/*
* Cannot initialize GVT device without intel_gvt_host gets
* initialized first.
*/
if (WARN_ON(!intel_gvt_host.initialized))
return -EINVAL;
if (WARN_ON(dev_priv->gvt))
return -EEXIST;
......@@ -420,13 +366,6 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
goto out_clean_types;
}
ret = intel_gvt_hypervisor_host_init(&dev_priv->drm.pdev->dev, gvt,
&intel_gvt_ops);
if (ret) {
gvt_err("failed to register gvt-g host device: %d\n", ret);
goto out_clean_types;
}
vgpu = intel_gvt_create_idle_vgpu(gvt);
if (IS_ERR(vgpu)) {
ret = PTR_ERR(vgpu);
......@@ -441,6 +380,8 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
gvt_dbg_core("gvt device initialization is done\n");
dev_priv->gvt = gvt;
intel_gvt_host.dev = &dev_priv->drm.pdev->dev;
intel_gvt_host.initialized = true;
return 0;
out_clean_types:
......@@ -467,6 +408,45 @@ int intel_gvt_init_device(struct drm_i915_private *dev_priv)
return ret;
}
#if IS_ENABLED(CONFIG_DRM_I915_GVT_KVMGT)
MODULE_SOFTDEP("pre: kvmgt");
#endif
int
intel_gvt_register_hypervisor(struct intel_gvt_mpt *m)
{
int ret;
void *gvt;
if (!intel_gvt_host.initialized)
return -ENODEV;
if (m->type != INTEL_GVT_HYPERVISOR_KVM &&
m->type != INTEL_GVT_HYPERVISOR_XEN)
return -EINVAL;
/* Get a reference for device model module */
if (!try_module_get(THIS_MODULE))
return -ENODEV;
intel_gvt_host.mpt = m;
intel_gvt_host.hypervisor_type = m->type;
gvt = (void *)kdev_to_i915(intel_gvt_host.dev)->gvt;
ret = intel_gvt_hypervisor_host_init(intel_gvt_host.dev, gvt,
&intel_gvt_ops);
if (ret < 0) {
gvt_err("Failed to init %s hypervisor module\n",
supported_hypervisors[intel_gvt_host.hypervisor_type]);
module_put(THIS_MODULE);
return -ENODEV;
}
gvt_dbg_core("Running with hypervisor %s in host mode\n",
supported_hypervisors[intel_gvt_host.hypervisor_type]);
return 0;
}
EXPORT_SYMBOL_GPL(intel_gvt_register_hypervisor);
void
intel_gvt_unregister_hypervisor(void)
{
intel_gvt_hypervisor_host_exit(intel_gvt_host.dev);
module_put(THIS_MODULE);
}
EXPORT_SYMBOL_GPL(intel_gvt_unregister_hypervisor);
......@@ -52,12 +52,8 @@
#define GVT_MAX_VGPU 8
enum {
INTEL_GVT_HYPERVISOR_XEN = 0,
INTEL_GVT_HYPERVISOR_KVM,
};
struct intel_gvt_host {
struct device *dev;
bool initialized;
int hypervisor_type;
struct intel_gvt_mpt *mpt;
......
......@@ -33,11 +33,17 @@
#ifndef _GVT_HYPERCALL_H_
#define _GVT_HYPERCALL_H_
enum hypervisor_type {
INTEL_GVT_HYPERVISOR_XEN = 0,
INTEL_GVT_HYPERVISOR_KVM,
};
/*
* Specific GVT-g MPT modules function collections. Currently GVT-g supports
* both Xen and KVM by providing dedicated hypervisor-related MPT modules.
*/
struct intel_gvt_mpt {
enum hypervisor_type type;
int (*host_init)(struct device *dev, void *gvt, const void *ops);
void (*host_exit)(struct device *dev);
int (*attach_vgpu)(void *vgpu, unsigned long *handle);
......@@ -67,6 +73,5 @@ struct intel_gvt_mpt {
};
extern struct intel_gvt_mpt xengt_mpt;
extern struct intel_gvt_mpt kvmgt_mpt;
#endif /* _GVT_HYPERCALL_H_ */
......@@ -627,6 +627,12 @@ static int intel_vgpu_open(struct mdev_device *mdev)
goto undo_iommu;
}
/* Take a module reference as mdev core doesn't take
* a reference for vendor driver.
*/
if (!try_module_get(THIS_MODULE))
goto undo_group;
ret = kvmgt_guest_init(mdev);
if (ret)
goto undo_group;
......@@ -679,6 +685,9 @@ static void __intel_vgpu_release(struct intel_vgpu *vgpu)
&vgpu->vdev.group_notifier);
WARN(ret, "vfio_unregister_notifier for group failed: %d\n", ret);
/* dereference module reference taken at open */
module_put(THIS_MODULE);
info = (struct kvmgt_guest_info *)vgpu->handle;
kvmgt_guest_exit(info);
......@@ -1849,7 +1858,8 @@ static bool kvmgt_is_valid_gfn(unsigned long handle, unsigned long gfn)
return ret;
}
struct intel_gvt_mpt kvmgt_mpt = {
static struct intel_gvt_mpt kvmgt_mpt = {
.type = INTEL_GVT_HYPERVISOR_KVM,
.host_init = kvmgt_host_init,
.host_exit = kvmgt_host_exit,
.attach_vgpu = kvmgt_attach_vgpu,
......@@ -1868,15 +1878,17 @@ struct intel_gvt_mpt kvmgt_mpt = {
.put_vfio_device = kvmgt_put_vfio_device,
.is_valid_gfn = kvmgt_is_valid_gfn,
};
EXPORT_SYMBOL_GPL(kvmgt_mpt);
static int __init kvmgt_init(void)
{
if (intel_gvt_register_hypervisor(&kvmgt_mpt) < 0)
return -ENODEV;
return 0;
}
static void __exit kvmgt_exit(void)
{
intel_gvt_unregister_hypervisor();
}
module_init(kvmgt_init);
......
......@@ -360,4 +360,7 @@ static inline bool intel_gvt_hypervisor_is_valid_gfn(
return intel_gvt_host.mpt->is_valid_gfn(vgpu->handle, gfn);
}
int intel_gvt_register_hypervisor(struct intel_gvt_mpt *);
void intel_gvt_unregister_hypervisor(void);
#endif /* _GVT_MPT_H_ */
......@@ -105,15 +105,6 @@ int intel_gvt_init(struct drm_i915_private *dev_priv)
return -EIO;
}
/*
* We're not in host or fail to find a MPT module, disable GVT-g
*/
ret = intel_gvt_init_host();
if (ret) {
DRM_DEBUG_DRIVER("Not in host or MPT modules not found\n");
goto bail;
}
ret = intel_gvt_init_device(dev_priv);
if (ret) {
DRM_DEBUG_DRIVER("Fail to init GVT device\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment