diff options
-rw-r--r-- | drivers/xen/Kconfig | 32 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/Makefile | 5 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/passthrough.c | 43 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/pciback.h | 94 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/vpci.c | 43 | ||||
-rw-r--r-- | drivers/xen/xen-pciback/xenbus.c | 21 |
6 files changed, 166 insertions, 72 deletions
diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig index 0b6989f9204..9b700b4a987 100644 --- a/drivers/xen/Kconfig +++ b/drivers/xen/Kconfig @@ -109,34 +109,22 @@ config XEN_PCIDEV_BACKEND tristate "Xen PCI-device backend driver" depends on PCI && X86 && XEN depends on XEN_BACKEND + default m help The PCI device backend driver allows the kernel to export arbitrary PCI devices to other guests. If you select this to be a module, you will need to make sure no other driver has bound to the device(s) you want to make visible to other guests. -choice - prompt "PCI Backend Mode" - depends on XEN_PCIDEV_BACKEND - -config XEN_PCIDEV_BACKEND_VPCI - bool "Virtual PCI" - help - This PCI Backend hides the true PCI topology and makes the frontend - think there is a single PCI bus with only the exported devices on it. - For example, a device at 03:05.0 will be re-assigned to 00:00.0. A - second device at 02:1a.1 will be re-assigned to 00:01.1. - -config XEN_PCIDEV_BACKEND_PASS - bool "Passthrough" - help - This PCI Backend provides a real view of the PCI topology to the - frontend (for example, a device at 06:01.b will still appear at - 06:01.b to the frontend). This is similar to how Xen 2.0.x exposed - PCI devices to its driver domains. This may be required for drivers - which depend on finding their hardward in certain bus/slot - locations. + The parameter "passthrough" allows you specify how you want the PCI + devices to appear in the guest. You can choose the default (0) where + PCI topology starts at 00.00.0, or (1) for passthrough if you want + the PCI devices topology appear the same as in the host. -endchoice + The "hide" parameter (only applicable if backend driver is compiled + into the kernel) allows you to bind the PCI devices to this module + from the default device drivers. The argument is the list of PCI BDFs: + xen-pciback.hide=(03:00.0)(04:00.0) + If in doubt, say m. endmenu diff --git a/drivers/xen/xen-pciback/Makefile b/drivers/xen/xen-pciback/Makefile index 290396766f0..ffe0ad3438b 100644 --- a/drivers/xen/xen-pciback/Makefile +++ b/drivers/xen/xen-pciback/Makefile @@ -3,6 +3,5 @@ obj-$(CONFIG_XEN_PCIDEV_BACKEND) += xen-pciback.o xen-pciback-y := pci_stub.o pciback_ops.o xenbus.o xen-pciback-y += conf_space.o conf_space_header.o \ conf_space_capability.o \ - conf_space_quirks.o -xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_VPCI) += vpci.o -xen-pciback-$(CONFIG_XEN_PCIDEV_BACKEND_PASS) += passthrough.o + conf_space_quirks.o vpci.o \ + passthrough.o diff --git a/drivers/xen/xen-pciback/passthrough.c b/drivers/xen/xen-pciback/passthrough.c index b451cb8dd2f..1d32a9a42c0 100644 --- a/drivers/xen/xen-pciback/passthrough.c +++ b/drivers/xen/xen-pciback/passthrough.c @@ -16,9 +16,10 @@ struct passthrough_dev_data { spinlock_t lock; }; -struct pci_dev *xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, - unsigned int domain, unsigned int bus, - unsigned int devfn) +static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, + unsigned int domain, + unsigned int bus, + unsigned int devfn) { struct passthrough_dev_data *dev_data = pdev->pci_dev_data; struct pci_dev_entry *dev_entry; @@ -41,8 +42,9 @@ struct pci_dev *xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, return dev; } -int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, - int devid, publish_pci_dev_cb publish_cb) +static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, + struct pci_dev *dev, + int devid, publish_pci_dev_cb publish_cb) { struct passthrough_dev_data *dev_data = pdev->pci_dev_data; struct pci_dev_entry *dev_entry; @@ -68,8 +70,8 @@ int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, return err; } -void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, - struct pci_dev *dev) +static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, + struct pci_dev *dev) { struct passthrough_dev_data *dev_data = pdev->pci_dev_data; struct pci_dev_entry *dev_entry, *t; @@ -92,7 +94,7 @@ void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, pcistub_put_pci_dev(found_dev); } -int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) +static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) { struct passthrough_dev_data *dev_data; @@ -109,8 +111,8 @@ int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) return 0; } -int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, - publish_pci_root_cb publish_root_cb) +static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, + publish_pci_root_cb publish_root_cb) { int err = 0; struct passthrough_dev_data *dev_data = pdev->pci_dev_data; @@ -154,7 +156,7 @@ int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, return err; } -void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) +static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) { struct passthrough_dev_data *dev_data = pdev->pci_dev_data; struct pci_dev_entry *dev_entry, *t; @@ -169,13 +171,24 @@ void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) pdev->pci_dev_data = NULL; } -int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, - struct xen_pcibk_device *pdev, - unsigned int *domain, unsigned int *bus, - unsigned int *devfn) +static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, + struct xen_pcibk_device *pdev, + unsigned int *domain, unsigned int *bus, + unsigned int *devfn) { *domain = pci_domain_nr(pcidev->bus); *bus = pcidev->bus->number; *devfn = pcidev->devfn; return 1; } + +struct xen_pcibk_backend xen_pcibk_passthrough_backend = { + .name = "passthrough", + .init = __xen_pcibk_init_devices, + .free = __xen_pcibk_release_devices, + .find = __xen_pcibk_get_pcifront_dev, + .publish = __xen_pcibk_publish_pci_roots, + .release = __xen_pcibk_release_pci_dev, + .add = __xen_pcibk_add_pci_dev, + .get = __xen_pcibk_get_pci_dev, +}; diff --git a/drivers/xen/xen-pciback/pciback.h b/drivers/xen/xen-pciback/pciback.h index 427b7fd0135..a0e131a8150 100644 --- a/drivers/xen/xen-pciback/pciback.h +++ b/drivers/xen/xen-pciback/pciback.h @@ -83,30 +83,90 @@ typedef int (*publish_pci_dev_cb) (struct xen_pcibk_device *pdev, unsigned int devfn, unsigned int devid); typedef int (*publish_pci_root_cb) (struct xen_pcibk_device *pdev, unsigned int domain, unsigned int bus); -int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, - int devid, publish_pci_dev_cb publish_cb); -void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, - struct pci_dev *dev); -struct pci_dev *xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, - unsigned int domain, unsigned int bus, - unsigned int devfn); +/* Backend registration for the two types of BDF representation: + * vpci - BDFs start at 00 + * passthrough - BDFs are exactly like in the host. + */ +struct xen_pcibk_backend { + char *name; + int (*init)(struct xen_pcibk_device *pdev); + void (*free)(struct xen_pcibk_device *pdev); + int (*find)(struct pci_dev *pcidev, struct xen_pcibk_device *pdev, + unsigned int *domain, unsigned int *bus, + unsigned int *devfn); + int (*publish)(struct xen_pcibk_device *pdev, publish_pci_root_cb cb); + void (*release)(struct xen_pcibk_device *pdev, struct pci_dev *dev); + int (*add)(struct xen_pcibk_device *pdev, struct pci_dev *dev, + int devid, publish_pci_dev_cb publish_cb); + struct pci_dev *(*get)(struct xen_pcibk_device *pdev, + unsigned int domain, unsigned int bus, + unsigned int devfn); +}; + +extern struct xen_pcibk_backend xen_pcibk_vpci_backend; +extern struct xen_pcibk_backend xen_pcibk_passthrough_backend; +extern struct xen_pcibk_backend *xen_pcibk_backend; + +static inline int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, + struct pci_dev *dev, + int devid, + publish_pci_dev_cb publish_cb) +{ + if (xen_pcibk_backend && xen_pcibk_backend->add) + return xen_pcibk_backend->add(pdev, dev, devid, publish_cb); + return -1; +}; +static inline void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, + struct pci_dev *dev) +{ + if (xen_pcibk_backend && xen_pcibk_backend->free) + return xen_pcibk_backend->release(pdev, dev); +}; + +static inline struct pci_dev * +xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, unsigned int domain, + unsigned int bus, unsigned int devfn) +{ + if (xen_pcibk_backend && xen_pcibk_backend->get) + return xen_pcibk_backend->get(pdev, domain, bus, devfn); + return NULL; +}; /** * Add for domain0 PCIE-AER handling. Get guest domain/bus/devfn in xen_pcibk * before sending aer request to pcifront, so that guest could identify * device, coopearte with xen_pcibk to finish aer recovery job if device driver * has the capability */ - -int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, - struct xen_pcibk_device *pdev, - unsigned int *domain, unsigned int *bus, - unsigned int *devfn); -int xen_pcibk_init_devices(struct xen_pcibk_device *pdev); -int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, - publish_pci_root_cb cb); -void xen_pcibk_release_devices(struct xen_pcibk_device *pdev); - +static inline int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, + struct xen_pcibk_device *pdev, + unsigned int *domain, + unsigned int *bus, + unsigned int *devfn) +{ + if (xen_pcibk_backend && xen_pcibk_backend->find) + return xen_pcibk_backend->find(pcidev, pdev, domain, bus, + devfn); + return -1; +}; +static inline int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) +{ + if (xen_pcibk_backend && xen_pcibk_backend->init) + return xen_pcibk_backend->init(pdev); + return -1; +}; +static inline int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, + publish_pci_root_cb cb) +{ + if (xen_pcibk_backend && xen_pcibk_backend->publish) + return xen_pcibk_backend->publish(pdev, cb); + return -1; +}; +static inline void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) +{ + if (xen_pcibk_backend && xen_pcibk_backend->free) + return xen_pcibk_backend->free(pdev); +}; /* Handles events from front-end */ irqreturn_t xen_pcibk_handle_event(int irq, void *dev_id); void xen_pcibk_do_op(struct work_struct *data); diff --git a/drivers/xen/xen-pciback/vpci.c b/drivers/xen/xen-pciback/vpci.c index 7d5c192a150..4a42cfb0959 100644 --- a/drivers/xen/xen-pciback/vpci.c +++ b/drivers/xen/xen-pciback/vpci.c @@ -25,9 +25,10 @@ static inline struct list_head *list_first(struct list_head *head) return head->next; } -struct pci_dev *xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, - unsigned int domain, unsigned int bus, - unsigned int devfn) +static struct pci_dev *__xen_pcibk_get_pci_dev(struct xen_pcibk_device *pdev, + unsigned int domain, + unsigned int bus, + unsigned int devfn) { struct pci_dev_entry *entry; struct pci_dev *dev = NULL; @@ -63,8 +64,9 @@ static inline int match_slot(struct pci_dev *l, struct pci_dev *r) return 0; } -int xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, struct pci_dev *dev, - int devid, publish_pci_dev_cb publish_cb) +static int __xen_pcibk_add_pci_dev(struct xen_pcibk_device *pdev, + struct pci_dev *dev, int devid, + publish_pci_dev_cb publish_cb) { int err = 0, slot, func = -1; struct pci_dev_entry *t, *dev_entry; @@ -137,8 +139,8 @@ out: return err; } -void xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, - struct pci_dev *dev) +static void __xen_pcibk_release_pci_dev(struct xen_pcibk_device *pdev, + struct pci_dev *dev) { int slot; struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; @@ -167,7 +169,7 @@ out: pcistub_put_pci_dev(found_dev); } -int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) +static int __xen_pcibk_init_devices(struct xen_pcibk_device *pdev) { int slot; struct vpci_dev_data *vpci_dev; @@ -186,14 +188,14 @@ int xen_pcibk_init_devices(struct xen_pcibk_device *pdev) return 0; } -int xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, - publish_pci_root_cb publish_cb) +static int __xen_pcibk_publish_pci_roots(struct xen_pcibk_device *pdev, + publish_pci_root_cb publish_cb) { /* The Virtual PCI bus has only one root */ return publish_cb(pdev, 0, 0); } -void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) +static void __xen_pcibk_release_devices(struct xen_pcibk_device *pdev) { int slot; struct vpci_dev_data *vpci_dev = pdev->pci_dev_data; @@ -212,10 +214,10 @@ void xen_pcibk_release_devices(struct xen_pcibk_device *pdev) pdev->pci_dev_data = NULL; } -int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, - struct xen_pcibk_device *pdev, - unsigned int *domain, unsigned int *bus, - unsigned int *devfn) +static int __xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, + struct xen_pcibk_device *pdev, + unsigned int *domain, unsigned int *bus, + unsigned int *devfn) { struct pci_dev_entry *entry; struct pci_dev *dev = NULL; @@ -244,3 +246,14 @@ int xen_pcibk_get_pcifront_dev(struct pci_dev *pcidev, spin_unlock_irqrestore(&vpci_dev->lock, flags); return found; } + +struct xen_pcibk_backend xen_pcibk_vpci_backend = { + .name = "vpci", + .init = __xen_pcibk_init_devices, + .free = __xen_pcibk_release_devices, + .find = __xen_pcibk_get_pcifront_dev, + .publish = __xen_pcibk_publish_pci_roots, + .release = __xen_pcibk_release_pci_dev, + .add = __xen_pcibk_add_pci_dev, + .get = __xen_pcibk_get_pci_dev, +}; diff --git a/drivers/xen/xen-pciback/xenbus.c b/drivers/xen/xen-pciback/xenbus.c index 1e5ba85c0d3..206c4ce030b 100644 --- a/drivers/xen/xen-pciback/xenbus.c +++ b/drivers/xen/xen-pciback/xenbus.c @@ -18,6 +18,21 @@ #define INVALID_EVTCHN_IRQ (-1) struct workqueue_struct *xen_pcibk_wq; +static int __read_mostly passthrough; +module_param(passthrough, bool, S_IRUGO); +MODULE_PARM_DESC(passthrough, + "Option to specify how to export PCI topology to guest:\n"\ + " 0 - (default) Hide the true PCI topology and makes the frontend\n"\ + " there is a single PCI bus with only the exported devices on it.\n"\ + " For example, a device at 03:05.0 will be re-assigned to 00:00.0\n"\ + " while second device at 02:1a.1 will be re-assigned to 00:01.1.\n"\ + " 1 - Passthrough provides a real view of the PCI topology to the\n"\ + " frontend (for example, a device at 06:01.b will still appear at\n"\ + " 06:01.b to the frontend). This is similar to how Xen 2.0.x\n"\ + " exposed PCI devices to its driver domains. This may be required\n"\ + " for drivers which depend on finding their hardward in certain\n"\ + " bus/slot locations."); + static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev) { struct xen_pcibk_device *pdev; @@ -710,6 +725,8 @@ static struct xenbus_driver xenbus_xen_pcibk_driver = { .otherend_changed = xen_pcibk_frontend_changed, }; +struct xen_pcibk_backend *xen_pcibk_backend; + int __init xen_pcibk_xenbus_register(void) { xen_pcibk_wq = create_workqueue("xen_pciback_workqueue"); @@ -718,6 +735,10 @@ int __init xen_pcibk_xenbus_register(void) "xen_pciback_workqueue failed\n", __func__); return -EFAULT; } + xen_pcibk_backend = &xen_pcibk_vpci_backend; + if (passthrough) + xen_pcibk_backend = &xen_pcibk_passthrough_backend; + pr_info(DRV_NAME ": backend is %s\n", xen_pcibk_backend->name); return xenbus_register_backend(&xenbus_xen_pcibk_driver); } |