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. ...@@ -409,6 +409,7 @@ Your cooperation is appreciated.
193 = /dev/d7s SPARC 7-segment display 193 = /dev/d7s SPARC 7-segment display
194 = /dev/zkshim Zero-Knowledge network shim control 194 = /dev/zkshim Zero-Knowledge network shim control
195 = /dev/elographics/e2201 Elographics touchscreen E271-2201 195 = /dev/elographics/e2201 Elographics touchscreen E271-2201
196 = /dev/vfio/vfio VFIO userspace driver interface
198 = /dev/sexec Signed executable interface 198 = /dev/sexec Signed executable interface
199 = /dev/scanners/cuecat :CueCat barcode scanner 199 = /dev/scanners/cuecat :CueCat barcode scanner
200 = /dev/net/tun TAP/TUN network device 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, ...@@ -872,9 +872,13 @@ static pci_ers_result_t vfio_pci_aer_err_detected(struct pci_dev *pdev,
return PCI_ERS_RESULT_DISCONNECT; return PCI_ERS_RESULT_DISCONNECT;
} }
mutex_lock(&vdev->igate);
if (vdev->err_trigger) if (vdev->err_trigger)
eventfd_signal(vdev->err_trigger, 1); eventfd_signal(vdev->err_trigger, 1);
mutex_unlock(&vdev->igate);
vfio_device_put(device); vfio_device_put(device);
return PCI_ERS_RESULT_CAN_RECOVER; return PCI_ERS_RESULT_CAN_RECOVER;
......
...@@ -749,54 +749,37 @@ static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev, ...@@ -749,54 +749,37 @@ static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
unsigned count, uint32_t flags, void *data) unsigned count, uint32_t flags, void *data)
{ {
int32_t fd = *(int32_t *)data; int32_t fd = *(int32_t *)data;
struct pci_dev *pdev = vdev->pdev;
if ((index != VFIO_PCI_ERR_IRQ_INDEX) || if ((index != VFIO_PCI_ERR_IRQ_INDEX) ||
!(flags & VFIO_IRQ_SET_DATA_TYPE_MASK)) !(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
return -EINVAL; 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 */ /* DATA_NONE/DATA_BOOL enables loopback testing */
if (flags & VFIO_IRQ_SET_DATA_NONE) { if (flags & VFIO_IRQ_SET_DATA_NONE) {
device_lock(&pdev->dev);
if (vdev->err_trigger) if (vdev->err_trigger)
eventfd_signal(vdev->err_trigger, 1); eventfd_signal(vdev->err_trigger, 1);
device_unlock(&pdev->dev);
return 0; return 0;
} else if (flags & VFIO_IRQ_SET_DATA_BOOL) { } else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
uint8_t trigger = *(uint8_t *)data; uint8_t trigger = *(uint8_t *)data;
device_lock(&pdev->dev);
if (trigger && vdev->err_trigger) if (trigger && vdev->err_trigger)
eventfd_signal(vdev->err_trigger, 1); eventfd_signal(vdev->err_trigger, 1);
device_unlock(&pdev->dev);
return 0; return 0;
} }
/* Handle SET_DATA_EVENTFD */ /* Handle SET_DATA_EVENTFD */
if (fd == -1) { if (fd == -1) {
device_lock(&pdev->dev);
if (vdev->err_trigger) if (vdev->err_trigger)
eventfd_ctx_put(vdev->err_trigger); eventfd_ctx_put(vdev->err_trigger);
vdev->err_trigger = NULL; vdev->err_trigger = NULL;
device_unlock(&pdev->dev);
return 0; return 0;
} else if (fd >= 0) { } else if (fd >= 0) {
struct eventfd_ctx *efdctx; struct eventfd_ctx *efdctx;
efdctx = eventfd_ctx_fdget(fd); efdctx = eventfd_ctx_fdget(fd);
if (IS_ERR(efdctx)) if (IS_ERR(efdctx))
return PTR_ERR(efdctx); return PTR_ERR(efdctx);
device_lock(&pdev->dev);
if (vdev->err_trigger) if (vdev->err_trigger)
eventfd_ctx_put(vdev->err_trigger); eventfd_ctx_put(vdev->err_trigger);
vdev->err_trigger = efdctx; vdev->err_trigger = efdctx;
device_unlock(&pdev->dev);
return 0; return 0;
} else } else
return -EINVAL; return -EINVAL;
......
...@@ -22,6 +22,7 @@ ...@@ -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 { ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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)
goto err_base_chrdev;
cdev_init(&vfio.cdev, &vfio_fops);
ret = cdev_add(&vfio.cdev, vfio.devt, 1);
if (ret) 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); 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) ...@@ -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) ...@@ -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); ...@@ -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");
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#define STORE_QUEUE_MINOR 155 #define STORE_QUEUE_MINOR 155
#define I2O_MINOR 166 #define I2O_MINOR 166
#define MICROCODE_MINOR 184 #define MICROCODE_MINOR 184
#define VFIO_MINOR 196
#define TUN_MINOR 200 #define TUN_MINOR 200
#define CUSE_MINOR 203 #define CUSE_MINOR 203
#define MWAVE_MINOR 219 /* ACP/Mwave Modem */ #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