Signed-off-by: Alex Williamson <alex.williamson@xxxxxxxxxx> --- drivers/vfio/Kconfig | 7 ++ drivers/vfio/Makefile | 1 drivers/vfio/vfio_main.c | 10 +++ drivers/vfio/vfio_pci.c | 124 +++++++++++++++++++++++++++++++++++++++++++ drivers/vfio/vfio_private.h | 5 ++ 5 files changed, 147 insertions(+), 0 deletions(-) create mode 100644 drivers/vfio/vfio_pci.c diff --git a/drivers/vfio/Kconfig b/drivers/vfio/Kconfig index a150521..b17bdbd 100644 --- a/drivers/vfio/Kconfig +++ b/drivers/vfio/Kconfig @@ -3,3 +3,10 @@ menuconfig VFIO depends on IOMMU_API help If you don't know what to do here, say N. + +menuconfig VFIO_PCI + bool "VFIO support for PCI devices" + depends on VFIO && PCI + default y if X86 + help + If you don't know what to do here, say N. diff --git a/drivers/vfio/Makefile b/drivers/vfio/Makefile index 5eaa074..90ee753 100644 --- a/drivers/vfio/Makefile +++ b/drivers/vfio/Makefile @@ -1,3 +1,4 @@ obj-$(CONFIG_VFIO) := vfio.o vfio-y := vfio_main.o vfio_iommu.o vfio_device.o +vfio-$(CONFIG_VFIO_PCI) += vfio_pci.o diff --git a/drivers/vfio/vfio_main.c b/drivers/vfio/vfio_main.c index 7f05692..c6e80f7 100644 --- a/drivers/vfio/vfio_main.c +++ b/drivers/vfio/vfio_main.c @@ -834,6 +834,12 @@ static int __init vfio_init(void) if (ret) goto err_cdev; +#ifdef CONFIG_VFIO_PCI + ret = vfio_pci_init(&vfio); + if (ret) + pr_debug(DRIVER_DESC "PCI init failed %d\n", ret); +#endif + pr_info(DRIVER_DESC " version: " DRIVER_VERSION "\n"); return 0; @@ -864,6 +870,10 @@ static void __exit vfio_cleanup(void) } } +#ifdef CONFIG_VFIO_PCI + vfio_pci_cleanup(&vfio); +#endif + idr_destroy(&vfio.idr); cdev_del(&vfio.cdev); unregister_chrdev_region(vfio.devt, MINORMASK); diff --git a/drivers/vfio/vfio_pci.c b/drivers/vfio/vfio_pci.c new file mode 100644 index 0000000..88325d0 --- /dev/null +++ b/drivers/vfio/vfio_pci.c @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2011 Red Hat, Inc. All rights reserved. + * Author: Alex Williamson <alex.williamson@xxxxxxxxxx> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Derived from original vfio: + * Copyright 2010 Cisco Systems, Inc. All rights reserved. + * Author: Tom Lyon, pugs@xxxxxxxxx + */ + +#include <linux/device.h> +#include <linux/notifier.h> +#include <linux/pci.h> +#include <linux/slab.h> +#include <linux/vfio.h> + +#include "vfio_private.h" + +struct vfio_pci_device { + struct vfio_device vdev; + struct pci_dev *pdev; +}; + +static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + return 0; +} + +static void vfio_pci_remove(struct pci_dev *pdev) +{ +} + +static struct pci_driver vfio_pci_driver = { + .name = "vfio", + .id_table = NULL, /* only dynamic id's */ + .probe = vfio_pci_probe, + .remove = vfio_pci_remove, +}; + +static struct vfio_device *vfio_pci_new(struct device *dev) +{ + struct vfio_pci_device *pvdev; + + pvdev = kzalloc(sizeof(*pvdev), GFP_KERNEL); + if (!pvdev) + return ERR_PTR(-ENOMEM); + + printk("%s: alloc pvdev @%p\n", __FUNCTION__, pvdev); + pvdev->pdev = container_of(dev, struct pci_dev, dev); + + // PCI stuff... + + return &pvdev->vdev; +} + +static void vfio_pci_free(struct vfio_device *vdev) +{ + struct vfio_pci_device *pvdev; + + pvdev = container_of(vdev, struct vfio_pci_device, vdev); + + // PCI stuff... + + printk("%s: freeing pvdev @%p\n", __FUNCTION__, pvdev); + kfree(pvdev); +} + +static const struct vfio_device_ops vfio_pci_ops = { + .new = vfio_pci_new, + .free = vfio_pci_free, +}; + +static int vfio_pci_device_notifier(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct device *dev = data; + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + + if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL) + return 0; + + if (action == BUS_NOTIFY_ADD_DEVICE) + return vfio_group_add_dev(dev, (void *)&vfio_pci_ops); + else if (action == BUS_NOTIFY_DEL_DEVICE) + vfio_group_del_dev(dev); + return 0; +} + +static int vfio_pci_add_dev(struct device *dev, void *unused) +{ + struct pci_dev *pdev = container_of(dev, struct pci_dev, dev); + + if (pdev->hdr_type != PCI_HEADER_TYPE_NORMAL) + return 0; + + return vfio_group_add_dev(dev, (void *)&vfio_pci_ops); +} + +static struct notifier_block vfio_pci_device_nb = { + .notifier_call = vfio_pci_device_notifier, +}; + +void __exit vfio_pci_cleanup(struct vfio *vfio) +{ + bus_unregister_notifier(&pci_bus_type, &vfio_pci_device_nb); + pci_unregister_driver(&vfio_pci_driver); +} + +int __init vfio_pci_init(struct vfio *vfio) +{ + int ret; + + ret = pci_register_driver(&vfio_pci_driver); + if (ret) + return ret; + + bus_register_notifier(&pci_bus_type, &vfio_pci_device_nb); + bus_for_each_dev(&pci_bus_type, NULL, NULL, vfio_pci_add_dev); + + return 0; +} diff --git a/drivers/vfio/vfio_private.h b/drivers/vfio/vfio_private.h index 2cc300c..85c88ea 100644 --- a/drivers/vfio/vfio_private.h +++ b/drivers/vfio/vfio_private.h @@ -79,4 +79,9 @@ struct vfio_group { extern int vfio_group_add_dev(struct device *dev, void *data); extern void vfio_group_del_dev(struct device *dev); +#ifdef CONFIG_VFIO_PCI +extern int vfio_pci_init(struct vfio *vfio); +extern void vfio_pci_cleanup(struct vfio *vfio); +#endif + #endif /* VFIO_PRIVATE_H */ -- To unsubscribe from this list: send the line "unsubscribe linux-pci" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html