Commit 2d08cd0e authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'vfio-v3.14-rc1' of git://github.com/awilliam/linux-vfio

Pull vfio update from Alex Williamson:
 - convert to misc driver to support module auto loading
 - remove unnecessary and dangerous use of device_lock

* tag 'vfio-v3.14-rc1' of git://github.com/awilliam/linux-vfio:
  vfio-pci: Don't use device_lock around AER interrupt setup
  vfio: Convert control interface to misc driver
  misc: Reserve minor for VFIO
parents 5c85121b 3be3a074
......@@ -409,6 +409,7 @@ Your cooperation is appreciated.
193 = /dev/d7s SPARC 7-segment display
194 = /dev/zkshim Zero-Knowledge network shim control
195 = /dev/elographics/e2201 Elographics touchscreen E271-2201
196 = /dev/vfio/vfio VFIO userspace driver interface
198 = /dev/sexec Signed executable interface
199 = /dev/scanners/cuecat :CueCat barcode scanner
200 = /dev/net/tun TAP/TUN network device
......
......@@ -872,9 +872,13 @@ static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,
return PCI_ERS_RESULT_DISCONNECT;
}
mutex_lock(&vdev->igate);
if (vdev->err_trigger)
eventfd_signal(vdev->err_trigger, 1);
mutex_unlock(&vdev->igate);
vfio_device_put(device);
return PCI_ERS_RESULT_CAN_RECOVER;
......
......@@ -749,54 +749,37 @@ static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
unsigned count, uint32_t flags, void *data)
{
int32_t fd = *(int32_t *)data;
struct pci_dev *pdev = vdev->pdev;
if ((index != VFIO_PCI_ERR_IRQ_INDEX) ||
!(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
return -EINVAL;
/*
* device_lock synchronizes setting and checking of
* err_trigger. The vfio_pci_aer_err_detected() is also
* called with device_lock held.
*/
/* DATA_NONE/DATA_BOOL enables loopback testing */
if (flags & VFIO_IRQ_SET_DATA_NONE) {
device_lock(&pdev->dev);
if (vdev->err_trigger)
eventfd_signal(vdev->err_trigger, 1);
device_unlock(&pdev->dev);
return 0;
} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
uint8_t trigger = *(uint8_t *)data;
device_lock(&pdev->dev);
if (trigger && vdev->err_trigger)
eventfd_signal(vdev->err_trigger, 1);
device_unlock(&pdev->dev);
return 0;
}
/* Handle SET_DATA_EVENTFD */
if (fd == -1) {
device_lock(&pdev->dev);
if (vdev->err_trigger)
eventfd_ctx_put(vdev->err_trigger);
vdev->err_trigger = NULL;
device_unlock(&pdev->dev);
return 0;
} else if (fd >= 0) {
struct eventfd_ctx *efdctx;
efdctx = eventfd_ctx_fdget(fd);
if (IS_ERR(efdctx))
return PTR_ERR(efdctx);
device_lock(&pdev->dev);
if (vdev->err_trigger)
eventfd_ctx_put(vdev->err_trigger);
vdev->err_trigger = efdctx;
device_unlock(&pdev->dev);
return 0;
} else
return -EINVAL;
......
......@@ -22,6 +22,7 @@
#include <linux/idr.h>
#include <linux/iommu.h>
#include <linux/list.h>
#include <linux/miscdevice.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/rwsem.h>
......@@ -45,9 +46,7 @@ static struct vfio {
struct idr group_idr;
struct mutex group_lock;
struct cdev group_cdev;
struct device *dev;
dev_t devt;
struct cdev cdev;
dev_t group_devt;
wait_queue_head_t release_q;
} vfio;
......@@ -142,8 +141,7 @@ EXPORT_SYMBOL_GPL(vfio_unregister_iommu_driver);
*/
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, 1, MINORMASK + 1, GFP_KERNEL);
return idr_alloc(&vfio.group_idr, group, 0, MINORMASK + 1, GFP_KERNEL);
}
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));
if (IS_ERR(dev)) {
vfio_free_group_minor(minor);
......@@ -268,7 +267,7 @@ static void vfio_group_release(struct kref *kref)
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);
vfio_free_group_minor(group->minor);
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)
{
if (mode && (MINOR(dev->devt) == 0))
*mode = S_IRUGO | S_IWUGO;
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)
{
int ret;
......@@ -1436,6 +1440,13 @@ static int __init vfio_init(void)
INIT_LIST_HEAD(&vfio.iommu_drivers_list);
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");
if (IS_ERR(vfio.class)) {
ret = PTR_ERR(vfio.class);
......@@ -1444,27 +1455,14 @@ static int __init vfio_init(void)
vfio.class->devnode = vfio_devnode;
ret = alloc_chrdev_region(&vfio.devt, 0, MINORMASK, "vfio");
if (ret)
goto err_base_chrdev;
cdev_init(&vfio.cdev, &vfio_fops);
ret = cdev_add(&vfio.cdev, vfio.devt, 1);
ret = alloc_chrdev_region(&vfio.group_devt, 0, MINORMASK, "vfio");
if (ret)
goto err_base_cdev;
goto err_alloc_chrdev;
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);
ret = cdev_add(&vfio.group_cdev,
MKDEV(MAJOR(vfio.devt), 1), MINORMASK - 1);
ret = cdev_add(&vfio.group_cdev, vfio.group_devt, MINORMASK);
if (ret)
goto err_groups_cdev;
goto err_cdev_add;
pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
......@@ -1478,16 +1476,13 @@ static int __init vfio_init(void)
return 0;
err_groups_cdev:
device_destroy(vfio.class, vfio.devt);
err_base_dev:
cdev_del(&vfio.cdev);
err_base_cdev:
unregister_chrdev_region(vfio.devt, MINORMASK);
err_base_chrdev:
err_cdev_add:
unregister_chrdev_region(vfio.group_devt, MINORMASK);
err_alloc_chrdev:
class_destroy(vfio.class);
vfio.class = NULL;
err_class:
misc_deregister(&vfio_dev);
return ret;
}
......@@ -1497,11 +1492,10 @@ static void __exit vfio_cleanup(void)
idr_destroy(&vfio.group_idr);
cdev_del(&vfio.group_cdev);
device_destroy(vfio.class, vfio.devt);
cdev_del(&vfio.cdev);
unregister_chrdev_region(vfio.devt, MINORMASK);
unregister_chrdev_region(vfio.group_devt, MINORMASK);
class_destroy(vfio.class);
vfio.class = NULL;
misc_deregister(&vfio_dev);
}
module_init(vfio_init);
......@@ -1511,3 +1505,5 @@ MODULE_VERSION(DRIVER_VERSION);
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_ALIAS_MISCDEV(VFIO_MINOR);
MODULE_ALIAS("devname:vfio/vfio");
......@@ -30,6 +30,7 @@
#define STORE_QUEUE_MINOR 155
#define I2O_MINOR 166
#define MICROCODE_MINOR 184
#define VFIO_MINOR 196
#define TUN_MINOR 200
#define CUSE_MINOR 203
#define MWAVE_MINOR 219 /* ACP/Mwave Modem */
......
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