diff options
Diffstat (limited to 'drivers/vfio/vfio.c')
-rw-r--r-- | drivers/vfio/vfio.c | 70 |
1 files changed, 33 insertions, 37 deletions
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c index 1eab4ace0671..21271d8df023 100644 --- a/drivers/vfio/vfio.c +++ b/drivers/vfio/vfio.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/idr.h> | 22 | #include <linux/idr.h> |
23 | #include <linux/iommu.h> | 23 | #include <linux/iommu.h> |
24 | #include <linux/list.h> | 24 | #include <linux/list.h> |
25 | #include <linux/miscdevice.h> | ||
25 | #include <linux/module.h> | 26 | #include <linux/module.h> |
26 | #include <linux/mutex.h> | 27 | #include <linux/mutex.h> |
27 | #include <linux/rwsem.h> | 28 | #include <linux/rwsem.h> |
@@ -45,9 +46,7 @@ static struct vfio { | |||
45 | struct idr group_idr; | 46 | struct idr group_idr; |
46 | struct mutex group_lock; | 47 | struct mutex group_lock; |
47 | struct cdev group_cdev; | 48 | struct cdev group_cdev; |
48 | struct device *dev; | 49 | dev_t group_devt; |
49 | dev_t devt; | ||
50 | struct cdev cdev; | ||
51 | wait_queue_head_t release_q; | 50 | wait_queue_head_t release_q; |
52 | } vfio; | 51 | } vfio; |
53 | 52 | ||
@@ -142,8 +141,7 @@ EXPORT_SYMBOL_GPL(vfio_unregister_iommu_driver); | |||
142 | */ | 141 | */ |
143 | static int vfio_alloc_group_minor(struct vfio_group *group) | 142 | static int vfio_alloc_group_minor(struct vfio_group *group) |
144 | { | 143 | { |
145 | /* index 0 is used by /dev/vfio/vfio */ | 144 | return idr_alloc(&vfio.group_idr, group, 0, MINORMASK + 1, GFP_KERNEL); |
146 | return idr_alloc(&vfio.group_idr, group, 1, MINORMASK + 1, GFP_KERNEL); | ||
147 | } | 145 | } |
148 | 146 | ||
149 | static void vfio_free_group_minor(int minor) | 147 | 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 | } | 241 | } |
244 | } | 242 | } |
245 | 243 | ||
246 | dev = device_create(vfio.class, NULL, MKDEV(MAJOR(vfio.devt), minor), | 244 | dev = device_create(vfio.class, NULL, |
245 | MKDEV(MAJOR(vfio.group_devt), minor), | ||
247 | group, "%d", iommu_group_id(iommu_group)); | 246 | group, "%d", iommu_group_id(iommu_group)); |
248 | if (IS_ERR(dev)) { | 247 | if (IS_ERR(dev)) { |
249 | vfio_free_group_minor(minor); | 248 | vfio_free_group_minor(minor); |
@@ -268,7 +267,7 @@ static void vfio_group_release(struct kref *kref) | |||
268 | 267 | ||
269 | WARN_ON(!list_empty(&group->device_list)); | 268 | WARN_ON(!list_empty(&group->device_list)); |
270 | 269 | ||
271 | device_destroy(vfio.class, MKDEV(MAJOR(vfio.devt), group->minor)); | 270 | device_destroy(vfio.class, MKDEV(MAJOR(vfio.group_devt), group->minor)); |
272 | list_del(&group->vfio_next); | 271 | list_del(&group->vfio_next); |
273 | vfio_free_group_minor(group->minor); | 272 | vfio_free_group_minor(group->minor); |
274 | vfio_group_unlock_and_free(group); | 273 | vfio_group_unlock_and_free(group); |
@@ -1419,12 +1418,17 @@ EXPORT_SYMBOL_GPL(vfio_external_user_iommu_id); | |||
1419 | */ | 1418 | */ |
1420 | static char *vfio_devnode(struct device *dev, umode_t *mode) | 1419 | static char *vfio_devnode(struct device *dev, umode_t *mode) |
1421 | { | 1420 | { |
1422 | if (mode && (MINOR(dev->devt) == 0)) | ||
1423 | *mode = S_IRUGO | S_IWUGO; | ||
1424 | |||
1425 | return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev)); | 1421 | return kasprintf(GFP_KERNEL, "vfio/%s", dev_name(dev)); |
1426 | } | 1422 | } |
1427 | 1423 | ||
1424 | static struct miscdevice vfio_dev = { | ||
1425 | .minor = VFIO_MINOR, | ||
1426 | .name = "vfio", | ||
1427 | .fops = &vfio_fops, | ||
1428 | .nodename = "vfio/vfio", | ||
1429 | .mode = S_IRUGO | S_IWUGO, | ||
1430 | }; | ||
1431 | |||
1428 | static int __init vfio_init(void) | 1432 | static int __init vfio_init(void) |
1429 | { | 1433 | { |
1430 | int ret; | 1434 | int ret; |
@@ -1436,6 +1440,13 @@ static int __init vfio_init(void) | |||
1436 | INIT_LIST_HEAD(&vfio.iommu_drivers_list); | 1440 | INIT_LIST_HEAD(&vfio.iommu_drivers_list); |
1437 | init_waitqueue_head(&vfio.release_q); | 1441 | init_waitqueue_head(&vfio.release_q); |
1438 | 1442 | ||
1443 | ret = misc_register(&vfio_dev); | ||
1444 | if (ret) { | ||
1445 | pr_err("vfio: misc device register failed\n"); | ||
1446 | return ret; | ||
1447 | } | ||
1448 | |||
1449 | /* /dev/vfio/$GROUP */ | ||
1439 | vfio.class = class_create(THIS_MODULE, "vfio"); | 1450 | vfio.class = class_create(THIS_MODULE, "vfio"); |
1440 | if (IS_ERR(vfio.class)) { | 1451 | if (IS_ERR(vfio.class)) { |
1441 | ret = PTR_ERR(vfio.class); | 1452 | ret = PTR_ERR(vfio.class); |
@@ -1444,27 +1455,14 @@ static int __init vfio_init(void) | |||
1444 | 1455 | ||
1445 | vfio.class->devnode = vfio_devnode; | 1456 | vfio.class->devnode = vfio_devnode; |
1446 | 1457 | ||
1447 | ret = alloc_chrdev_region(&vfio.devt, 0, MINORMASK, "vfio"); | 1458 | ret = alloc_chrdev_region(&vfio.group_devt, 0, MINORMASK, "vfio"); |
1448 | if (ret) | ||
1449 | goto err_base_chrdev; | ||
1450 | |||
1451 | cdev_init(&vfio.cdev, &vfio_fops); | ||
1452 | ret = cdev_add(&vfio.cdev, vfio.devt, 1); | ||
1453 | if (ret) | 1459 | if (ret) |
1454 | goto err_base_cdev; | 1460 | goto err_alloc_chrdev; |
1455 | 1461 | ||
1456 | vfio.dev = device_create(vfio.class, NULL, vfio.devt, NULL, "vfio"); | ||
1457 | if (IS_ERR(vfio.dev)) { | ||
1458 | ret = PTR_ERR(vfio.dev); | ||
1459 | goto err_base_dev; | ||
1460 | } | ||
1461 | |||
1462 | /* /dev/vfio/$GROUP */ | ||
1463 | cdev_init(&vfio.group_cdev, &vfio_group_fops); | 1462 | cdev_init(&vfio.group_cdev, &vfio_group_fops); |
1464 | ret = cdev_add(&vfio.group_cdev, | 1463 | ret = cdev_add(&vfio.group_cdev, vfio.group_devt, MINORMASK); |
1465 | MKDEV(MAJOR(vfio.devt), 1), MINORMASK - 1); | ||
1466 | if (ret) | 1464 | if (ret) |
1467 | goto err_groups_cdev; | 1465 | goto err_cdev_add; |
1468 | 1466 | ||
1469 | pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); | 1467 | pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); |
1470 | 1468 | ||
@@ -1478,16 +1476,13 @@ static int __init vfio_init(void) | |||
1478 | 1476 | ||
1479 | return 0; | 1477 | return 0; |
1480 | 1478 | ||
1481 | err_groups_cdev: | 1479 | err_cdev_add: |
1482 | device_destroy(vfio.class, vfio.devt); | 1480 | unregister_chrdev_region(vfio.group_devt, MINORMASK); |
1483 | err_base_dev: | 1481 | err_alloc_chrdev: |
1484 | cdev_del(&vfio.cdev); | ||
1485 | err_base_cdev: | ||
1486 | unregister_chrdev_region(vfio.devt, MINORMASK); | ||
1487 | err_base_chrdev: | ||
1488 | class_destroy(vfio.class); | 1482 | class_destroy(vfio.class); |
1489 | vfio.class = NULL; | 1483 | vfio.class = NULL; |
1490 | err_class: | 1484 | err_class: |
1485 | misc_deregister(&vfio_dev); | ||
1491 | return ret; | 1486 | return ret; |
1492 | } | 1487 | } |
1493 | 1488 | ||
@@ -1497,11 +1492,10 @@ static void __exit vfio_cleanup(void) | |||
1497 | 1492 | ||
1498 | idr_destroy(&vfio.group_idr); | 1493 | idr_destroy(&vfio.group_idr); |
1499 | cdev_del(&vfio.group_cdev); | 1494 | cdev_del(&vfio.group_cdev); |
1500 | device_destroy(vfio.class, vfio.devt); | 1495 | unregister_chrdev_region(vfio.group_devt, MINORMASK); |
1501 | cdev_del(&vfio.cdev); | ||
1502 | unregister_chrdev_region(vfio.devt, MINORMASK); | ||
1503 | class_destroy(vfio.class); | 1496 | class_destroy(vfio.class); |
1504 | vfio.class = NULL; | 1497 | vfio.class = NULL; |
1498 | misc_deregister(&vfio_dev); | ||
1505 | } | 1499 | } |
1506 | 1500 | ||
1507 | module_init(vfio_init); | 1501 | module_init(vfio_init); |
@@ -1511,3 +1505,5 @@ MODULE_VERSION(DRIVER_VERSION); | |||
1511 | MODULE_LICENSE("GPL v2"); | 1505 | MODULE_LICENSE("GPL v2"); |
1512 | MODULE_AUTHOR(DRIVER_AUTHOR); | 1506 | MODULE_AUTHOR(DRIVER_AUTHOR); |
1513 | MODULE_DESCRIPTION(DRIVER_DESC); | 1507 | MODULE_DESCRIPTION(DRIVER_DESC); |
1508 | MODULE_ALIAS_MISCDEV(VFIO_MINOR); | ||
1509 | MODULE_ALIAS("devname:vfio/vfio"); | ||