vfio: Convert control interface to misc driver
This change allows us to support module auto loading using devname support in userspace tools. With this, /dev/vfio/vfio will always be present and opening it will cause the vfio module to load. This should avoid needing to configure the system to statically load vfio in order to get libvirt to correctly detect support for it. Suggested-by: Paolo Bonzini <pbonzini@redhat.com> Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
This commit is contained in:
parent
8dcf94bcff
commit
d10999016f
1 changed files with 33 additions and 37 deletions
|
@ -22,6 +22,7 @@
|
||||||
#include <linux/idr.h>
|
#include <linux/idr.h>
|
||||||
#include <linux/iommu.h>
|
#include <linux/iommu.h>
|
||||||
#include <linux/list.h>
|
#include <linux/list.h>
|
||||||
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/mutex.h>
|
#include <linux/mutex.h>
|
||||||
#include <linux/rwsem.h>
|
#include <linux/rwsem.h>
|
||||||
|
@ -45,9 +46,7 @@ static struct vfio {
|
||||||
struct idr group_idr;
|
struct idr group_idr;
|
||||||
struct mutex group_lock;
|
struct mutex group_lock;
|
||||||
struct cdev group_cdev;
|
struct cdev group_cdev;
|
||||||
struct device *dev;
|
dev_t group_devt;
|
||||||
dev_t devt;
|
|
||||||
struct cdev cdev;
|
|
||||||
wait_queue_head_t release_q;
|
wait_queue_head_t release_q;
|
||||||
} vfio;
|
} vfio;
|
||||||
|
|
||||||
|
@ -142,8 +141,7 @@ EXPORT_SYMBOL_GPL(vfio_unregister_iommu_driver);
|
||||||
*/
|
*/
|
||||||
static int vfio_alloc_group_minor(struct vfio_group *group)
|
static int vfio_alloc_group_minor(struct vfio_group *group)
|
||||||
{
|
{
|
||||||
/* index 0 is used by /dev/vfio/vfio */
|
return idr_alloc(&vfio.group_idr, group, 0, MINORMASK + 1, GFP_KERNEL);
|
||||||
return idr_alloc(&vfio.group_idr, group, 1, MINORMASK + 1, GFP_KERNEL);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vfio_free_group_minor(int minor)
|
static void vfio_free_group_minor(int minor)
|
||||||
|
@ -243,7 +241,8 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dev = device_create(vfio.class, NULL, MKDEV(MAJOR(vfio.devt), minor),
|
dev = device_create(vfio.class, NULL,
|
||||||
|
MKDEV(MAJOR(vfio.group_devt), minor),
|
||||||
group, "%d", iommu_group_id(iommu_group));
|
group, "%d", iommu_group_id(iommu_group));
|
||||||
if (IS_ERR(dev)) {
|
if (IS_ERR(dev)) {
|
||||||
vfio_free_group_minor(minor);
|
vfio_free_group_minor(minor);
|
||||||
|
@ -268,7 +267,7 @@ static void vfio_group_release(struct kref *kref)
|
||||||
|
|
||||||
WARN_ON(!list_empty(&group->device_list));
|
WARN_ON(!list_empty(&group->device_list));
|
||||||
|
|
||||||
device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor));
|
device_destroy(vfio.class, MKDEV(MAJOR(vfio.group_devt), group->minor));
|
||||||
list_del(&group->vfio_next);
|
list_del(&group->vfio_next);
|
||||||
vfio_free_group_minor(group->minor);
|
vfio_free_group_minor(group->minor);
|
||||||
vfio_group_unlock_and_free(group);
|
vfio_group_unlock_and_free(group);
|
||||||
|
@ -1419,12 +1418,17 @@ EXPORT_SYMBOL_GPL(vfio_external_user_iommu_id);
|
||||||
*/
|
*/
|
||||||
static char *vfio_devnode(struct device *dev, umode_t *mode)
|
static char *vfio_devnode(struct device *dev, umode_t *mode)
|
||||||
{
|
{
|
||||||
if (mode && (MINOR(dev->devt) == 0))
|
|
||||||
*mode = S_IRUGO | S_IWUGO;
|
|
||||||
|
|
||||||
return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev));
|
return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static struct miscdevice vfio_dev = {
|
||||||
|
.minor = VFIO_MINOR,
|
||||||
|
.name = "vfio",
|
||||||
|
.fops = &vfio_fops,
|
||||||
|
.nodename = "vfio/vfio",
|
||||||
|
.mode = S_IRUGO | S_IWUGO,
|
||||||
|
};
|
||||||
|
|
||||||
static int __init vfio_init(void)
|
static int __init vfio_init(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1436,6 +1440,13 @@ static int __init vfio_init(void)
|
||||||
INIT_LIST_HEAD(&vfio.iommu_drivers_list);
|
INIT_LIST_HEAD(&vfio.iommu_drivers_list);
|
||||||
init_waitqueue_head(&vfio.release_q);
|
init_waitqueue_head(&vfio.release_q);
|
||||||
|
|
||||||
|
ret = misc_register(&vfio_dev);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("vfio: misc device register failed\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* /dev/vfio/$GROUP */
|
||||||
vfio.class = class_create(THIS_MODULE, "vfio");
|
vfio.class = class_create(THIS_MODULE, "vfio");
|
||||||
if (IS_ERR(vfio.class)) {
|
if (IS_ERR(vfio.class)) {
|
||||||
ret = PTR_ERR(vfio.class);
|
ret = PTR_ERR(vfio.class);
|
||||||
|
@ -1444,27 +1455,14 @@ static int __init vfio_init(void)
|
||||||
|
|
||||||
vfio.class->devnode = vfio_devnode;
|
vfio.class->devnode = vfio_devnode;
|
||||||
|
|
||||||
ret = alloc_chrdev_region(&vfio.devt, 0, MINORMASK, "vfio");
|
ret = alloc_chrdev_region(&vfio.group_devt, 0, MINORMASK, "vfio");
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_base_chrdev;
|
goto err_alloc_chrdev;
|
||||||
|
|
||||||
cdev_init(&vfio.cdev, &vfio_fops);
|
|
||||||
ret = cdev_add(&vfio.cdev, vfio.devt, 1);
|
|
||||||
if (ret)
|
|
||||||
goto err_base_cdev;
|
|
||||||
|
|
||||||
vfio.dev = device_create(vfio.class, NULL, vfio.devt, NULL, "vfio");
|
|
||||||
if (IS_ERR(vfio.dev)) {
|
|
||||||
ret = PTR_ERR(vfio.dev);
|
|
||||||
goto err_base_dev;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* /dev/vfio/$GROUP */
|
|
||||||
cdev_init(&vfio.group_cdev, &vfio_group_fops);
|
cdev_init(&vfio.group_cdev, &vfio_group_fops);
|
||||||
ret = cdev_add(&vfio.group_cdev,
|
ret = cdev_add(&vfio.group_cdev, vfio.group_devt, MINORMASK);
|
||||||
MKDEV(MAJOR(vfio.devt), 1), MINORMASK - 1);
|
|
||||||
if (ret)
|
if (ret)
|
||||||
goto err_groups_cdev;
|
goto err_cdev_add;
|
||||||
|
|
||||||
pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
|
pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
|
||||||
|
|
||||||
|
@ -1478,16 +1476,13 @@ static int __init vfio_init(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
err_groups_cdev:
|
err_cdev_add:
|
||||||
device_destroy(vfio.class, vfio.devt);
|
unregister_chrdev_region(vfio.group_devt, MINORMASK);
|
||||||
err_base_dev:
|
err_alloc_chrdev:
|
||||||
cdev_del(&vfio.cdev);
|
|
||||||
err_base_cdev:
|
|
||||||
unregister_chrdev_region(vfio.devt, MINORMASK);
|
|
||||||
err_base_chrdev:
|
|
||||||
class_destroy(vfio.class);
|
class_destroy(vfio.class);
|
||||||
vfio.class = NULL;
|
vfio.class = NULL;
|
||||||
err_class:
|
err_class:
|
||||||
|
misc_deregister(&vfio_dev);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1497,11 +1492,10 @@ static void __exit vfio_cleanup(void)
|
||||||
|
|
||||||
idr_destroy(&vfio.group_idr);
|
idr_destroy(&vfio.group_idr);
|
||||||
cdev_del(&vfio.group_cdev);
|
cdev_del(&vfio.group_cdev);
|
||||||
device_destroy(vfio.class, vfio.devt);
|
unregister_chrdev_region(vfio.group_devt, MINORMASK);
|
||||||
cdev_del(&vfio.cdev);
|
|
||||||
unregister_chrdev_region(vfio.devt, MINORMASK);
|
|
||||||
class_destroy(vfio.class);
|
class_destroy(vfio.class);
|
||||||
vfio.class = NULL;
|
vfio.class = NULL;
|
||||||
|
misc_deregister(&vfio_dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
module_init(vfio_init);
|
module_init(vfio_init);
|
||||||
|
@ -1511,3 +1505,5 @@ MODULE_VERSION(DRIVER_VERSION);
|
||||||
MODULE_LICENSE("GPL v2");
|
MODULE_LICENSE("GPL v2");
|
||||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||||
|
MODULE_ALIAS_MISCDEV(VFIO_MINOR);
|
||||||
|
MODULE_ALIAS("devname:vfio/vfio");
|
||||||
|
|
Loading…
Add table
Reference in a new issue