1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 230edc14bSKonrad Rzeszutek Wilk /* 330edc14bSKonrad Rzeszutek Wilk * PCI Backend Xenbus Setup - handles setup with frontend and xend 430edc14bSKonrad Rzeszutek Wilk * 530edc14bSKonrad Rzeszutek Wilk * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 630edc14bSKonrad Rzeszutek Wilk */ 7283c0972SJoe Perches 8283c0972SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9283c0972SJoe Perches 1059aa56bfSPaul Gortmaker #include <linux/moduleparam.h> 1130edc14bSKonrad Rzeszutek Wilk #include <linux/init.h> 1230edc14bSKonrad Rzeszutek Wilk #include <linux/list.h> 1330edc14bSKonrad Rzeszutek Wilk #include <linux/vmalloc.h> 1430edc14bSKonrad Rzeszutek Wilk #include <linux/workqueue.h> 1530edc14bSKonrad Rzeszutek Wilk #include <xen/xenbus.h> 1630edc14bSKonrad Rzeszutek Wilk #include <xen/events.h> 17*a67efff2SOleksandr Andrushchenko #include <xen/pci.h> 1830edc14bSKonrad Rzeszutek Wilk #include "pciback.h" 1930edc14bSKonrad Rzeszutek Wilk 2030edc14bSKonrad Rzeszutek Wilk #define INVALID_EVTCHN_IRQ (-1) 2130edc14bSKonrad Rzeszutek Wilk 2290ab5ee9SRusty Russell static bool __read_mostly passthrough; 232ebdc426SKonrad Rzeszutek Wilk module_param(passthrough, bool, S_IRUGO); 242ebdc426SKonrad Rzeszutek Wilk MODULE_PARM_DESC(passthrough, 252ebdc426SKonrad Rzeszutek Wilk "Option to specify how to export PCI topology to guest:\n"\ 262ebdc426SKonrad Rzeszutek Wilk " 0 - (default) Hide the true PCI topology and makes the frontend\n"\ 272ebdc426SKonrad Rzeszutek Wilk " there is a single PCI bus with only the exported devices on it.\n"\ 282ebdc426SKonrad Rzeszutek Wilk " For example, a device at 03:05.0 will be re-assigned to 00:00.0\n"\ 292ebdc426SKonrad Rzeszutek Wilk " while second device at 02:1a.1 will be re-assigned to 00:01.1.\n"\ 302ebdc426SKonrad Rzeszutek Wilk " 1 - Passthrough provides a real view of the PCI topology to the\n"\ 312ebdc426SKonrad Rzeszutek Wilk " frontend (for example, a device at 06:01.b will still appear at\n"\ 322ebdc426SKonrad Rzeszutek Wilk " 06:01.b to the frontend). This is similar to how Xen 2.0.x\n"\ 332ebdc426SKonrad Rzeszutek Wilk " exposed PCI devices to its driver domains. This may be required\n"\ 342ebdc426SKonrad Rzeszutek Wilk " for drivers which depend on finding their hardward in certain\n"\ 352ebdc426SKonrad Rzeszutek Wilk " bus/slot locations."); 362ebdc426SKonrad Rzeszutek Wilk 37a92336a1SKonrad Rzeszutek Wilk static struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev) 3830edc14bSKonrad Rzeszutek Wilk { 39a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev; 4030edc14bSKonrad Rzeszutek Wilk 41a92336a1SKonrad Rzeszutek Wilk pdev = kzalloc(sizeof(struct xen_pcibk_device), GFP_KERNEL); 4230edc14bSKonrad Rzeszutek Wilk if (pdev == NULL) 4330edc14bSKonrad Rzeszutek Wilk goto out; 4430edc14bSKonrad Rzeszutek Wilk dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev); 4530edc14bSKonrad Rzeszutek Wilk 4630edc14bSKonrad Rzeszutek Wilk pdev->xdev = xdev; 4730edc14bSKonrad Rzeszutek Wilk 48b1766b62SKonrad Rzeszutek Wilk mutex_init(&pdev->dev_lock); 4930edc14bSKonrad Rzeszutek Wilk 5030edc14bSKonrad Rzeszutek Wilk pdev->sh_info = NULL; 5130edc14bSKonrad Rzeszutek Wilk pdev->evtchn_irq = INVALID_EVTCHN_IRQ; 5230edc14bSKonrad Rzeszutek Wilk pdev->be_watching = 0; 5330edc14bSKonrad Rzeszutek Wilk 54a92336a1SKonrad Rzeszutek Wilk INIT_WORK(&pdev->op_work, xen_pcibk_do_op); 5530edc14bSKonrad Rzeszutek Wilk 56a92336a1SKonrad Rzeszutek Wilk if (xen_pcibk_init_devices(pdev)) { 5730edc14bSKonrad Rzeszutek Wilk kfree(pdev); 5830edc14bSKonrad Rzeszutek Wilk pdev = NULL; 5930edc14bSKonrad Rzeszutek Wilk } 60584a561aSDoug Goldstein 61584a561aSDoug Goldstein dev_set_drvdata(&xdev->dev, pdev); 62584a561aSDoug Goldstein 6330edc14bSKonrad Rzeszutek Wilk out: 6430edc14bSKonrad Rzeszutek Wilk return pdev; 6530edc14bSKonrad Rzeszutek Wilk } 6630edc14bSKonrad Rzeszutek Wilk 67a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_disconnect(struct xen_pcibk_device *pdev) 6830edc14bSKonrad Rzeszutek Wilk { 69b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 7030edc14bSKonrad Rzeszutek Wilk /* Ensure the guest can't trigger our handler before removing devices */ 7130edc14bSKonrad Rzeszutek Wilk if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) { 7230edc14bSKonrad Rzeszutek Wilk unbind_from_irqhandler(pdev->evtchn_irq, pdev); 7330edc14bSKonrad Rzeszutek Wilk pdev->evtchn_irq = INVALID_EVTCHN_IRQ; 7430edc14bSKonrad Rzeszutek Wilk } 7530edc14bSKonrad Rzeszutek Wilk 7630edc14bSKonrad Rzeszutek Wilk /* If the driver domain started an op, make sure we complete it 7730edc14bSKonrad Rzeszutek Wilk * before releasing the shared memory */ 78494ef20dSKonrad Rzeszutek Wilk 79429eafe6SBhaktipriya Shridhar flush_work(&pdev->op_work); 8030edc14bSKonrad Rzeszutek Wilk 8130edc14bSKonrad Rzeszutek Wilk if (pdev->sh_info != NULL) { 8230edc14bSKonrad Rzeszutek Wilk xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info); 8330edc14bSKonrad Rzeszutek Wilk pdev->sh_info = NULL; 8430edc14bSKonrad Rzeszutek Wilk } 85b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 8630edc14bSKonrad Rzeszutek Wilk } 8730edc14bSKonrad Rzeszutek Wilk 88a92336a1SKonrad Rzeszutek Wilk static void free_pdev(struct xen_pcibk_device *pdev) 8930edc14bSKonrad Rzeszutek Wilk { 90494ef20dSKonrad Rzeszutek Wilk if (pdev->be_watching) { 9130edc14bSKonrad Rzeszutek Wilk unregister_xenbus_watch(&pdev->be_watch); 92494ef20dSKonrad Rzeszutek Wilk pdev->be_watching = 0; 93494ef20dSKonrad Rzeszutek Wilk } 9430edc14bSKonrad Rzeszutek Wilk 95a92336a1SKonrad Rzeszutek Wilk xen_pcibk_disconnect(pdev); 9630edc14bSKonrad Rzeszutek Wilk 978be9df6dSKonrad Rzeszutek Wilk /* N.B. This calls pcistub_put_pci_dev which does the FLR on all 988be9df6dSKonrad Rzeszutek Wilk * of the PCIe devices. */ 99a92336a1SKonrad Rzeszutek Wilk xen_pcibk_release_devices(pdev); 10030edc14bSKonrad Rzeszutek Wilk 10130edc14bSKonrad Rzeszutek Wilk dev_set_drvdata(&pdev->xdev->dev, NULL); 10230edc14bSKonrad Rzeszutek Wilk pdev->xdev = NULL; 10330edc14bSKonrad Rzeszutek Wilk 10430edc14bSKonrad Rzeszutek Wilk kfree(pdev); 10530edc14bSKonrad Rzeszutek Wilk } 10630edc14bSKonrad Rzeszutek Wilk 107a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref, 1080102e4efSYan Yankovskyi evtchn_port_t remote_evtchn) 10930edc14bSKonrad Rzeszutek Wilk { 11030edc14bSKonrad Rzeszutek Wilk int err = 0; 11130edc14bSKonrad Rzeszutek Wilk void *vaddr; 11230edc14bSKonrad Rzeszutek Wilk 11330edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, 1140102e4efSYan Yankovskyi "Attaching to frontend resources - gnt_ref=%d evtchn=%u\n", 11530edc14bSKonrad Rzeszutek Wilk gnt_ref, remote_evtchn); 11630edc14bSKonrad Rzeszutek Wilk 117ccc9d90aSWei Liu err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr); 11830edc14bSKonrad Rzeszutek Wilk if (err < 0) { 11930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 12030edc14bSKonrad Rzeszutek Wilk "Error mapping other domain page in ours."); 12130edc14bSKonrad Rzeszutek Wilk goto out; 12230edc14bSKonrad Rzeszutek Wilk } 123494ef20dSKonrad Rzeszutek Wilk 12430edc14bSKonrad Rzeszutek Wilk pdev->sh_info = vaddr; 12530edc14bSKonrad Rzeszutek Wilk 126c2711441SJuergen Gross err = bind_interdomain_evtchn_to_irqhandler_lateeoi( 127f2fa0e5eSJuergen Gross pdev->xdev, remote_evtchn, xen_pcibk_handle_event, 128a92336a1SKonrad Rzeszutek Wilk 0, DRV_NAME, pdev); 12930edc14bSKonrad Rzeszutek Wilk if (err < 0) { 13030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 13130edc14bSKonrad Rzeszutek Wilk "Error binding event channel to IRQ"); 13230edc14bSKonrad Rzeszutek Wilk goto out; 13330edc14bSKonrad Rzeszutek Wilk } 13430edc14bSKonrad Rzeszutek Wilk pdev->evtchn_irq = err; 13530edc14bSKonrad Rzeszutek Wilk err = 0; 13630edc14bSKonrad Rzeszutek Wilk 13730edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Attached!\n"); 13830edc14bSKonrad Rzeszutek Wilk out: 13930edc14bSKonrad Rzeszutek Wilk return err; 14030edc14bSKonrad Rzeszutek Wilk } 14130edc14bSKonrad Rzeszutek Wilk 142a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_attach(struct xen_pcibk_device *pdev) 14330edc14bSKonrad Rzeszutek Wilk { 14430edc14bSKonrad Rzeszutek Wilk int err = 0; 1450102e4efSYan Yankovskyi int gnt_ref; 1460102e4efSYan Yankovskyi evtchn_port_t remote_evtchn; 14730edc14bSKonrad Rzeszutek Wilk char *magic = NULL; 14830edc14bSKonrad Rzeszutek Wilk 14930edc14bSKonrad Rzeszutek Wilk 150b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 15130edc14bSKonrad Rzeszutek Wilk /* Make sure we only do this setup once */ 15230edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->nodename) != 15330edc14bSKonrad Rzeszutek Wilk XenbusStateInitialised) 15430edc14bSKonrad Rzeszutek Wilk goto out; 15530edc14bSKonrad Rzeszutek Wilk 15630edc14bSKonrad Rzeszutek Wilk /* Wait for frontend to state that it has published the configuration */ 15730edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->otherend) != 15830edc14bSKonrad Rzeszutek Wilk XenbusStateInitialised) 15930edc14bSKonrad Rzeszutek Wilk goto out; 16030edc14bSKonrad Rzeszutek Wilk 16130edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Reading frontend config\n"); 16230edc14bSKonrad Rzeszutek Wilk 16330edc14bSKonrad Rzeszutek Wilk err = xenbus_gather(XBT_NIL, pdev->xdev->otherend, 16430edc14bSKonrad Rzeszutek Wilk "pci-op-ref", "%u", &gnt_ref, 16530edc14bSKonrad Rzeszutek Wilk "event-channel", "%u", &remote_evtchn, 16630edc14bSKonrad Rzeszutek Wilk "magic", NULL, &magic, NULL); 16730edc14bSKonrad Rzeszutek Wilk if (err) { 16830edc14bSKonrad Rzeszutek Wilk /* If configuration didn't get read correctly, wait longer */ 16930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 17030edc14bSKonrad Rzeszutek Wilk "Error reading configuration from frontend"); 17130edc14bSKonrad Rzeszutek Wilk goto out; 17230edc14bSKonrad Rzeszutek Wilk } 17330edc14bSKonrad Rzeszutek Wilk 17430edc14bSKonrad Rzeszutek Wilk if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) { 17530edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, -EFAULT, 17630edc14bSKonrad Rzeszutek Wilk "version mismatch (%s/%s) with pcifront - " 177402c5e15SJan Beulich "halting " DRV_NAME, 17830edc14bSKonrad Rzeszutek Wilk magic, XEN_PCI_MAGIC); 1792ef76032SWei Yongjun err = -EFAULT; 18030edc14bSKonrad Rzeszutek Wilk goto out; 18130edc14bSKonrad Rzeszutek Wilk } 18230edc14bSKonrad Rzeszutek Wilk 183a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn); 18430edc14bSKonrad Rzeszutek Wilk if (err) 18530edc14bSKonrad Rzeszutek Wilk goto out; 18630edc14bSKonrad Rzeszutek Wilk 18730edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Connecting...\n"); 18830edc14bSKonrad Rzeszutek Wilk 18930edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); 19030edc14bSKonrad Rzeszutek Wilk if (err) 19130edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 19230edc14bSKonrad Rzeszutek Wilk "Error switching to connected state!"); 19330edc14bSKonrad Rzeszutek Wilk 19430edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err); 19530edc14bSKonrad Rzeszutek Wilk out: 196b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 19730edc14bSKonrad Rzeszutek Wilk 19830edc14bSKonrad Rzeszutek Wilk kfree(magic); 19930edc14bSKonrad Rzeszutek Wilk 20030edc14bSKonrad Rzeszutek Wilk return err; 20130edc14bSKonrad Rzeszutek Wilk } 20230edc14bSKonrad Rzeszutek Wilk 203a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev, 20430edc14bSKonrad Rzeszutek Wilk unsigned int domain, unsigned int bus, 20530edc14bSKonrad Rzeszutek Wilk unsigned int devfn, unsigned int devid) 20630edc14bSKonrad Rzeszutek Wilk { 20730edc14bSKonrad Rzeszutek Wilk int err; 20830edc14bSKonrad Rzeszutek Wilk int len; 20930edc14bSKonrad Rzeszutek Wilk char str[64]; 21030edc14bSKonrad Rzeszutek Wilk 21130edc14bSKonrad Rzeszutek Wilk len = snprintf(str, sizeof(str), "vdev-%d", devid); 21230edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(str) - 1))) { 21330edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 21430edc14bSKonrad Rzeszutek Wilk goto out; 21530edc14bSKonrad Rzeszutek Wilk } 21630edc14bSKonrad Rzeszutek Wilk 217e4de866aSKonrad Rzeszutek Wilk /* Note: The PV protocol uses %02x, don't change it */ 21830edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, 21930edc14bSKonrad Rzeszutek Wilk "%04x:%02x:%02x.%02x", domain, bus, 22030edc14bSKonrad Rzeszutek Wilk PCI_SLOT(devfn), PCI_FUNC(devfn)); 22130edc14bSKonrad Rzeszutek Wilk 22230edc14bSKonrad Rzeszutek Wilk out: 22330edc14bSKonrad Rzeszutek Wilk return err; 22430edc14bSKonrad Rzeszutek Wilk } 22530edc14bSKonrad Rzeszutek Wilk 226a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_export_device(struct xen_pcibk_device *pdev, 22730edc14bSKonrad Rzeszutek Wilk int domain, int bus, int slot, int func, 22830edc14bSKonrad Rzeszutek Wilk int devid) 22930edc14bSKonrad Rzeszutek Wilk { 23030edc14bSKonrad Rzeszutek Wilk struct pci_dev *dev; 23130edc14bSKonrad Rzeszutek Wilk int err = 0; 23230edc14bSKonrad Rzeszutek Wilk 23330edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n", 23430edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 23530edc14bSKonrad Rzeszutek Wilk 23630edc14bSKonrad Rzeszutek Wilk dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func); 23730edc14bSKonrad Rzeszutek Wilk if (!dev) { 23830edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 23930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 24030edc14bSKonrad Rzeszutek Wilk "Couldn't locate PCI device " 241e4de866aSKonrad Rzeszutek Wilk "(%04x:%02x:%02x.%d)! " 24230edc14bSKonrad Rzeszutek Wilk "perhaps already in-use?", 24330edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 24430edc14bSKonrad Rzeszutek Wilk goto out; 24530edc14bSKonrad Rzeszutek Wilk } 24630edc14bSKonrad Rzeszutek Wilk 247a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_add_pci_dev(pdev, dev, devid, 248a92336a1SKonrad Rzeszutek Wilk xen_pcibk_publish_pci_dev); 24930edc14bSKonrad Rzeszutek Wilk if (err) 25030edc14bSKonrad Rzeszutek Wilk goto out; 25130edc14bSKonrad Rzeszutek Wilk 25215390613SKonrad Rzeszutek Wilk dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id); 2536221a9b2SKonrad Rzeszutek Wilk if (xen_register_device_domain_owner(dev, 2546221a9b2SKonrad Rzeszutek Wilk pdev->xdev->otherend_id) != 0) { 2556c254de1SKonrad Rzeszutek Wilk dev_err(&dev->dev, "Stealing ownership from dom%d.\n", 2566c254de1SKonrad Rzeszutek Wilk xen_find_device_domain_owner(dev)); 2576221a9b2SKonrad Rzeszutek Wilk xen_unregister_device_domain_owner(dev); 2586221a9b2SKonrad Rzeszutek Wilk xen_register_device_domain_owner(dev, pdev->xdev->otherend_id); 2596221a9b2SKonrad Rzeszutek Wilk } 2606221a9b2SKonrad Rzeszutek Wilk 26130edc14bSKonrad Rzeszutek Wilk /* TODO: It'd be nice to export a bridge and have all of its children 26230edc14bSKonrad Rzeszutek Wilk * get exported with it. This may be best done in xend (which will 26330edc14bSKonrad Rzeszutek Wilk * have to calculate resource usage anyway) but we probably want to 26430edc14bSKonrad Rzeszutek Wilk * put something in here to ensure that if a bridge gets given to a 26530edc14bSKonrad Rzeszutek Wilk * driver domain, that all devices under that bridge are not given 26630edc14bSKonrad Rzeszutek Wilk * to other driver domains (as he who controls the bridge can disable 26730edc14bSKonrad Rzeszutek Wilk * it and stop the other devices from working). 26830edc14bSKonrad Rzeszutek Wilk */ 26930edc14bSKonrad Rzeszutek Wilk out: 27030edc14bSKonrad Rzeszutek Wilk return err; 27130edc14bSKonrad Rzeszutek Wilk } 27230edc14bSKonrad Rzeszutek Wilk 273a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev, 27430edc14bSKonrad Rzeszutek Wilk int domain, int bus, int slot, int func) 27530edc14bSKonrad Rzeszutek Wilk { 27630edc14bSKonrad Rzeszutek Wilk int err = 0; 27730edc14bSKonrad Rzeszutek Wilk struct pci_dev *dev; 27830edc14bSKonrad Rzeszutek Wilk 27930edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n", 28030edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 28130edc14bSKonrad Rzeszutek Wilk 282a92336a1SKonrad Rzeszutek Wilk dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func)); 28330edc14bSKonrad Rzeszutek Wilk if (!dev) { 28430edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 28530edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device " 286e4de866aSKonrad Rzeszutek Wilk "(%04x:%02x:%02x.%d)! not owned by this domain\n", 28730edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 28830edc14bSKonrad Rzeszutek Wilk goto out; 28930edc14bSKonrad Rzeszutek Wilk } 29030edc14bSKonrad Rzeszutek Wilk 2916221a9b2SKonrad Rzeszutek Wilk dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id); 2926221a9b2SKonrad Rzeszutek Wilk xen_unregister_device_domain_owner(dev); 2936221a9b2SKonrad Rzeszutek Wilk 2948be9df6dSKonrad Rzeszutek Wilk /* N.B. This ends up calling pcistub_put_pci_dev which ends up 2958be9df6dSKonrad Rzeszutek Wilk * doing the FLR. */ 296e8801a74SKonrad Rzeszutek Wilk xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */); 29730edc14bSKonrad Rzeszutek Wilk 29830edc14bSKonrad Rzeszutek Wilk out: 29930edc14bSKonrad Rzeszutek Wilk return err; 30030edc14bSKonrad Rzeszutek Wilk } 30130edc14bSKonrad Rzeszutek Wilk 302a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev, 30330edc14bSKonrad Rzeszutek Wilk unsigned int domain, unsigned int bus) 30430edc14bSKonrad Rzeszutek Wilk { 30530edc14bSKonrad Rzeszutek Wilk unsigned int d, b; 30630edc14bSKonrad Rzeszutek Wilk int i, root_num, len, err; 30730edc14bSKonrad Rzeszutek Wilk char str[64]; 30830edc14bSKonrad Rzeszutek Wilk 30930edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n"); 31030edc14bSKonrad Rzeszutek Wilk 31130edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 31230edc14bSKonrad Rzeszutek Wilk "root_num", "%d", &root_num); 31330edc14bSKonrad Rzeszutek Wilk if (err == 0 || err == -ENOENT) 31430edc14bSKonrad Rzeszutek Wilk root_num = 0; 31530edc14bSKonrad Rzeszutek Wilk else if (err < 0) 31630edc14bSKonrad Rzeszutek Wilk goto out; 31730edc14bSKonrad Rzeszutek Wilk 31830edc14bSKonrad Rzeszutek Wilk /* Verify that we haven't already published this pci root */ 31930edc14bSKonrad Rzeszutek Wilk for (i = 0; i < root_num; i++) { 32030edc14bSKonrad Rzeszutek Wilk len = snprintf(str, sizeof(str), "root-%d", i); 32130edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(str) - 1))) { 32230edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 32330edc14bSKonrad Rzeszutek Wilk goto out; 32430edc14bSKonrad Rzeszutek Wilk } 32530edc14bSKonrad Rzeszutek Wilk 32630edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 32730edc14bSKonrad Rzeszutek Wilk str, "%x:%x", &d, &b); 32830edc14bSKonrad Rzeszutek Wilk if (err < 0) 32930edc14bSKonrad Rzeszutek Wilk goto out; 33030edc14bSKonrad Rzeszutek Wilk if (err != 2) { 33130edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 33230edc14bSKonrad Rzeszutek Wilk goto out; 33330edc14bSKonrad Rzeszutek Wilk } 33430edc14bSKonrad Rzeszutek Wilk 33530edc14bSKonrad Rzeszutek Wilk if (d == domain && b == bus) { 33630edc14bSKonrad Rzeszutek Wilk err = 0; 33730edc14bSKonrad Rzeszutek Wilk goto out; 33830edc14bSKonrad Rzeszutek Wilk } 33930edc14bSKonrad Rzeszutek Wilk } 34030edc14bSKonrad Rzeszutek Wilk 34130edc14bSKonrad Rzeszutek Wilk len = snprintf(str, sizeof(str), "root-%d", root_num); 34230edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(str) - 1))) { 34330edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 34430edc14bSKonrad Rzeszutek Wilk goto out; 34530edc14bSKonrad Rzeszutek Wilk } 34630edc14bSKonrad Rzeszutek Wilk 34730edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n", 34830edc14bSKonrad Rzeszutek Wilk root_num, domain, bus); 34930edc14bSKonrad Rzeszutek Wilk 35030edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, 35130edc14bSKonrad Rzeszutek Wilk "%04x:%02x", domain, bus); 35230edc14bSKonrad Rzeszutek Wilk if (err) 35330edc14bSKonrad Rzeszutek Wilk goto out; 35430edc14bSKonrad Rzeszutek Wilk 35530edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, 35630edc14bSKonrad Rzeszutek Wilk "root_num", "%d", (root_num + 1)); 35730edc14bSKonrad Rzeszutek Wilk 35830edc14bSKonrad Rzeszutek Wilk out: 35930edc14bSKonrad Rzeszutek Wilk return err; 36030edc14bSKonrad Rzeszutek Wilk } 36130edc14bSKonrad Rzeszutek Wilk 362c81d3d24SJan Beulich static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev, 363c81d3d24SJan Beulich enum xenbus_state state) 36430edc14bSKonrad Rzeszutek Wilk { 36530edc14bSKonrad Rzeszutek Wilk int err = 0; 36630edc14bSKonrad Rzeszutek Wilk int num_devs; 36730edc14bSKonrad Rzeszutek Wilk int domain, bus, slot, func; 3684e81f1caSJuergen Gross unsigned int substate; 36930edc14bSKonrad Rzeszutek Wilk int i, len; 37030edc14bSKonrad Rzeszutek Wilk char state_str[64]; 37130edc14bSKonrad Rzeszutek Wilk char dev_str[64]; 37230edc14bSKonrad Rzeszutek Wilk 37330edc14bSKonrad Rzeszutek Wilk 37430edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n"); 37530edc14bSKonrad Rzeszutek Wilk 376b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 377c81d3d24SJan Beulich if (xenbus_read_driver_state(pdev->xdev->nodename) != state) 37830edc14bSKonrad Rzeszutek Wilk goto out; 37930edc14bSKonrad Rzeszutek Wilk 38030edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", 38130edc14bSKonrad Rzeszutek Wilk &num_devs); 38230edc14bSKonrad Rzeszutek Wilk if (err != 1) { 38330edc14bSKonrad Rzeszutek Wilk if (err >= 0) 38430edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 38530edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 38630edc14bSKonrad Rzeszutek Wilk "Error reading number of devices"); 38730edc14bSKonrad Rzeszutek Wilk goto out; 38830edc14bSKonrad Rzeszutek Wilk } 38930edc14bSKonrad Rzeszutek Wilk 39030edc14bSKonrad Rzeszutek Wilk for (i = 0; i < num_devs; i++) { 39130edc14bSKonrad Rzeszutek Wilk len = snprintf(state_str, sizeof(state_str), "state-%d", i); 39230edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(state_str) - 1))) { 39330edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 39430edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 39530edc14bSKonrad Rzeszutek Wilk "String overflow while reading " 39630edc14bSKonrad Rzeszutek Wilk "configuration"); 39730edc14bSKonrad Rzeszutek Wilk goto out; 39830edc14bSKonrad Rzeszutek Wilk } 3994e81f1caSJuergen Gross substate = xenbus_read_unsigned(pdev->xdev->nodename, state_str, 4004e81f1caSJuergen Gross XenbusStateUnknown); 40130edc14bSKonrad Rzeszutek Wilk 40230edc14bSKonrad Rzeszutek Wilk switch (substate) { 40330edc14bSKonrad Rzeszutek Wilk case XenbusStateInitialising: 40430edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i); 40530edc14bSKonrad Rzeszutek Wilk 40630edc14bSKonrad Rzeszutek Wilk len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); 40730edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(dev_str) - 1))) { 40830edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 40930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 41030edc14bSKonrad Rzeszutek Wilk "String overflow while " 41130edc14bSKonrad Rzeszutek Wilk "reading configuration"); 41230edc14bSKonrad Rzeszutek Wilk goto out; 41330edc14bSKonrad Rzeszutek Wilk } 41430edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 41530edc14bSKonrad Rzeszutek Wilk dev_str, "%x:%x:%x.%x", 41630edc14bSKonrad Rzeszutek Wilk &domain, &bus, &slot, &func); 41730edc14bSKonrad Rzeszutek Wilk if (err < 0) { 41830edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 41930edc14bSKonrad Rzeszutek Wilk "Error reading device " 42030edc14bSKonrad Rzeszutek Wilk "configuration"); 42130edc14bSKonrad Rzeszutek Wilk goto out; 42230edc14bSKonrad Rzeszutek Wilk } 42330edc14bSKonrad Rzeszutek Wilk if (err != 4) { 42430edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 42530edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 42630edc14bSKonrad Rzeszutek Wilk "Error parsing pci device " 42730edc14bSKonrad Rzeszutek Wilk "configuration"); 42830edc14bSKonrad Rzeszutek Wilk goto out; 42930edc14bSKonrad Rzeszutek Wilk } 43030edc14bSKonrad Rzeszutek Wilk 431a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_export_device(pdev, domain, bus, slot, 43230edc14bSKonrad Rzeszutek Wilk func, i); 43330edc14bSKonrad Rzeszutek Wilk if (err) 43430edc14bSKonrad Rzeszutek Wilk goto out; 43530edc14bSKonrad Rzeszutek Wilk 43630edc14bSKonrad Rzeszutek Wilk /* Publish pci roots. */ 437a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_publish_pci_roots(pdev, 438a92336a1SKonrad Rzeszutek Wilk xen_pcibk_publish_pci_root); 43930edc14bSKonrad Rzeszutek Wilk if (err) { 44030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 44130edc14bSKonrad Rzeszutek Wilk "Error while publish PCI root" 44230edc14bSKonrad Rzeszutek Wilk "buses for frontend"); 44330edc14bSKonrad Rzeszutek Wilk goto out; 44430edc14bSKonrad Rzeszutek Wilk } 44530edc14bSKonrad Rzeszutek Wilk 44630edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, 44730edc14bSKonrad Rzeszutek Wilk state_str, "%d", 44830edc14bSKonrad Rzeszutek Wilk XenbusStateInitialised); 44930edc14bSKonrad Rzeszutek Wilk if (err) { 45030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 45130edc14bSKonrad Rzeszutek Wilk "Error switching substate of " 45230edc14bSKonrad Rzeszutek Wilk "dev-%d\n", i); 45330edc14bSKonrad Rzeszutek Wilk goto out; 45430edc14bSKonrad Rzeszutek Wilk } 45530edc14bSKonrad Rzeszutek Wilk break; 45630edc14bSKonrad Rzeszutek Wilk 45730edc14bSKonrad Rzeszutek Wilk case XenbusStateClosing: 45830edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i); 45930edc14bSKonrad Rzeszutek Wilk 46030edc14bSKonrad Rzeszutek Wilk len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i); 46130edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(dev_str) - 1))) { 46230edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 46330edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 46430edc14bSKonrad Rzeszutek Wilk "String overflow while " 46530edc14bSKonrad Rzeszutek Wilk "reading configuration"); 46630edc14bSKonrad Rzeszutek Wilk goto out; 46730edc14bSKonrad Rzeszutek Wilk } 46830edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 46930edc14bSKonrad Rzeszutek Wilk dev_str, "%x:%x:%x.%x", 47030edc14bSKonrad Rzeszutek Wilk &domain, &bus, &slot, &func); 47130edc14bSKonrad Rzeszutek Wilk if (err < 0) { 47230edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 47330edc14bSKonrad Rzeszutek Wilk "Error reading device " 47430edc14bSKonrad Rzeszutek Wilk "configuration"); 47530edc14bSKonrad Rzeszutek Wilk goto out; 47630edc14bSKonrad Rzeszutek Wilk } 47730edc14bSKonrad Rzeszutek Wilk if (err != 4) { 47830edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 47930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 48030edc14bSKonrad Rzeszutek Wilk "Error parsing pci device " 48130edc14bSKonrad Rzeszutek Wilk "configuration"); 48230edc14bSKonrad Rzeszutek Wilk goto out; 48330edc14bSKonrad Rzeszutek Wilk } 48430edc14bSKonrad Rzeszutek Wilk 485a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_remove_device(pdev, domain, bus, slot, 48630edc14bSKonrad Rzeszutek Wilk func); 48730edc14bSKonrad Rzeszutek Wilk if (err) 48830edc14bSKonrad Rzeszutek Wilk goto out; 48930edc14bSKonrad Rzeszutek Wilk 49030edc14bSKonrad Rzeszutek Wilk /* TODO: If at some point we implement support for pci 49130edc14bSKonrad Rzeszutek Wilk * root hot-remove on pcifront side, we'll need to 49230edc14bSKonrad Rzeszutek Wilk * remove unnecessary xenstore nodes of pci roots here. 49330edc14bSKonrad Rzeszutek Wilk */ 49430edc14bSKonrad Rzeszutek Wilk 49530edc14bSKonrad Rzeszutek Wilk break; 49630edc14bSKonrad Rzeszutek Wilk 49730edc14bSKonrad Rzeszutek Wilk default: 49830edc14bSKonrad Rzeszutek Wilk break; 49930edc14bSKonrad Rzeszutek Wilk } 50030edc14bSKonrad Rzeszutek Wilk } 50130edc14bSKonrad Rzeszutek Wilk 502c81d3d24SJan Beulich if (state != XenbusStateReconfiguring) 503c81d3d24SJan Beulich /* Make sure we only reconfigure once. */ 504c81d3d24SJan Beulich goto out; 505c81d3d24SJan Beulich 50630edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured); 50730edc14bSKonrad Rzeszutek Wilk if (err) { 50830edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 50930edc14bSKonrad Rzeszutek Wilk "Error switching to reconfigured state!"); 51030edc14bSKonrad Rzeszutek Wilk goto out; 51130edc14bSKonrad Rzeszutek Wilk } 51230edc14bSKonrad Rzeszutek Wilk 51330edc14bSKonrad Rzeszutek Wilk out: 514b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 51530edc14bSKonrad Rzeszutek Wilk return 0; 51630edc14bSKonrad Rzeszutek Wilk } 51730edc14bSKonrad Rzeszutek Wilk 518a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_frontend_changed(struct xenbus_device *xdev, 51930edc14bSKonrad Rzeszutek Wilk enum xenbus_state fe_state) 52030edc14bSKonrad Rzeszutek Wilk { 521a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev); 52230edc14bSKonrad Rzeszutek Wilk 52330edc14bSKonrad Rzeszutek Wilk dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state); 52430edc14bSKonrad Rzeszutek Wilk 52530edc14bSKonrad Rzeszutek Wilk switch (fe_state) { 52630edc14bSKonrad Rzeszutek Wilk case XenbusStateInitialised: 527a92336a1SKonrad Rzeszutek Wilk xen_pcibk_attach(pdev); 52830edc14bSKonrad Rzeszutek Wilk break; 52930edc14bSKonrad Rzeszutek Wilk 53030edc14bSKonrad Rzeszutek Wilk case XenbusStateReconfiguring: 531c81d3d24SJan Beulich xen_pcibk_reconfigure(pdev, XenbusStateReconfiguring); 53230edc14bSKonrad Rzeszutek Wilk break; 53330edc14bSKonrad Rzeszutek Wilk 53430edc14bSKonrad Rzeszutek Wilk case XenbusStateConnected: 53530edc14bSKonrad Rzeszutek Wilk /* pcifront switched its state from reconfiguring to connected. 53630edc14bSKonrad Rzeszutek Wilk * Then switch to connected state. 53730edc14bSKonrad Rzeszutek Wilk */ 53830edc14bSKonrad Rzeszutek Wilk xenbus_switch_state(xdev, XenbusStateConnected); 53930edc14bSKonrad Rzeszutek Wilk break; 54030edc14bSKonrad Rzeszutek Wilk 54130edc14bSKonrad Rzeszutek Wilk case XenbusStateClosing: 542a92336a1SKonrad Rzeszutek Wilk xen_pcibk_disconnect(pdev); 54330edc14bSKonrad Rzeszutek Wilk xenbus_switch_state(xdev, XenbusStateClosing); 54430edc14bSKonrad Rzeszutek Wilk break; 54530edc14bSKonrad Rzeszutek Wilk 54630edc14bSKonrad Rzeszutek Wilk case XenbusStateClosed: 547a92336a1SKonrad Rzeszutek Wilk xen_pcibk_disconnect(pdev); 54830edc14bSKonrad Rzeszutek Wilk xenbus_switch_state(xdev, XenbusStateClosed); 54930edc14bSKonrad Rzeszutek Wilk if (xenbus_dev_is_online(xdev)) 55030edc14bSKonrad Rzeszutek Wilk break; 551df561f66SGustavo A. R. Silva fallthrough; /* if not online */ 55230edc14bSKonrad Rzeszutek Wilk case XenbusStateUnknown: 55330edc14bSKonrad Rzeszutek Wilk dev_dbg(&xdev->dev, "frontend is gone! unregister device\n"); 55430edc14bSKonrad Rzeszutek Wilk device_unregister(&xdev->dev); 55530edc14bSKonrad Rzeszutek Wilk break; 55630edc14bSKonrad Rzeszutek Wilk 55730edc14bSKonrad Rzeszutek Wilk default: 55830edc14bSKonrad Rzeszutek Wilk break; 55930edc14bSKonrad Rzeszutek Wilk } 56030edc14bSKonrad Rzeszutek Wilk } 56130edc14bSKonrad Rzeszutek Wilk 562a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev) 56330edc14bSKonrad Rzeszutek Wilk { 56430edc14bSKonrad Rzeszutek Wilk /* Get configuration from xend (if available now) */ 56530edc14bSKonrad Rzeszutek Wilk int domain, bus, slot, func; 56630edc14bSKonrad Rzeszutek Wilk int err = 0; 56730edc14bSKonrad Rzeszutek Wilk int i, num_devs; 56830edc14bSKonrad Rzeszutek Wilk char dev_str[64]; 56930edc14bSKonrad Rzeszutek Wilk char state_str[64]; 57030edc14bSKonrad Rzeszutek Wilk 571b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 57230edc14bSKonrad Rzeszutek Wilk /* It's possible we could get the call to setup twice, so make sure 57330edc14bSKonrad Rzeszutek Wilk * we're not already connected. 57430edc14bSKonrad Rzeszutek Wilk */ 57530edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->nodename) != 57630edc14bSKonrad Rzeszutek Wilk XenbusStateInitWait) 57730edc14bSKonrad Rzeszutek Wilk goto out; 57830edc14bSKonrad Rzeszutek Wilk 57930edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "getting be setup\n"); 58030edc14bSKonrad Rzeszutek Wilk 58130edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", 58230edc14bSKonrad Rzeszutek Wilk &num_devs); 58330edc14bSKonrad Rzeszutek Wilk if (err != 1) { 58430edc14bSKonrad Rzeszutek Wilk if (err >= 0) 58530edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 58630edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 58730edc14bSKonrad Rzeszutek Wilk "Error reading number of devices"); 58830edc14bSKonrad Rzeszutek Wilk goto out; 58930edc14bSKonrad Rzeszutek Wilk } 59030edc14bSKonrad Rzeszutek Wilk 59130edc14bSKonrad Rzeszutek Wilk for (i = 0; i < num_devs; i++) { 59230edc14bSKonrad Rzeszutek Wilk int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); 59330edc14bSKonrad Rzeszutek Wilk if (unlikely(l >= (sizeof(dev_str) - 1))) { 59430edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 59530edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 59630edc14bSKonrad Rzeszutek Wilk "String overflow while reading " 59730edc14bSKonrad Rzeszutek Wilk "configuration"); 59830edc14bSKonrad Rzeszutek Wilk goto out; 59930edc14bSKonrad Rzeszutek Wilk } 60030edc14bSKonrad Rzeszutek Wilk 60130edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str, 60230edc14bSKonrad Rzeszutek Wilk "%x:%x:%x.%x", &domain, &bus, &slot, &func); 60330edc14bSKonrad Rzeszutek Wilk if (err < 0) { 60430edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 60530edc14bSKonrad Rzeszutek Wilk "Error reading device configuration"); 60630edc14bSKonrad Rzeszutek Wilk goto out; 60730edc14bSKonrad Rzeszutek Wilk } 60830edc14bSKonrad Rzeszutek Wilk if (err != 4) { 60930edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 61030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 61130edc14bSKonrad Rzeszutek Wilk "Error parsing pci device " 61230edc14bSKonrad Rzeszutek Wilk "configuration"); 61330edc14bSKonrad Rzeszutek Wilk goto out; 61430edc14bSKonrad Rzeszutek Wilk } 61530edc14bSKonrad Rzeszutek Wilk 616a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i); 61730edc14bSKonrad Rzeszutek Wilk if (err) 61830edc14bSKonrad Rzeszutek Wilk goto out; 61930edc14bSKonrad Rzeszutek Wilk 62030edc14bSKonrad Rzeszutek Wilk /* Switch substate of this device. */ 62130edc14bSKonrad Rzeszutek Wilk l = snprintf(state_str, sizeof(state_str), "state-%d", i); 62230edc14bSKonrad Rzeszutek Wilk if (unlikely(l >= (sizeof(state_str) - 1))) { 62330edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 62430edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 62530edc14bSKonrad Rzeszutek Wilk "String overflow while reading " 62630edc14bSKonrad Rzeszutek Wilk "configuration"); 62730edc14bSKonrad Rzeszutek Wilk goto out; 62830edc14bSKonrad Rzeszutek Wilk } 62930edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str, 63030edc14bSKonrad Rzeszutek Wilk "%d", XenbusStateInitialised); 63130edc14bSKonrad Rzeszutek Wilk if (err) { 63230edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, "Error switching " 63330edc14bSKonrad Rzeszutek Wilk "substate of dev-%d\n", i); 63430edc14bSKonrad Rzeszutek Wilk goto out; 63530edc14bSKonrad Rzeszutek Wilk } 63630edc14bSKonrad Rzeszutek Wilk } 63730edc14bSKonrad Rzeszutek Wilk 638a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root); 63930edc14bSKonrad Rzeszutek Wilk if (err) { 64030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 64130edc14bSKonrad Rzeszutek Wilk "Error while publish PCI root buses " 64230edc14bSKonrad Rzeszutek Wilk "for frontend"); 64330edc14bSKonrad Rzeszutek Wilk goto out; 64430edc14bSKonrad Rzeszutek Wilk } 64530edc14bSKonrad Rzeszutek Wilk 64630edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised); 64730edc14bSKonrad Rzeszutek Wilk if (err) 64830edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 64930edc14bSKonrad Rzeszutek Wilk "Error switching to initialised state!"); 65030edc14bSKonrad Rzeszutek Wilk 65130edc14bSKonrad Rzeszutek Wilk out: 652b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 65330edc14bSKonrad Rzeszutek Wilk if (!err) 65430edc14bSKonrad Rzeszutek Wilk /* see if pcifront is already configured (if not, we'll wait) */ 655a92336a1SKonrad Rzeszutek Wilk xen_pcibk_attach(pdev); 65630edc14bSKonrad Rzeszutek Wilk return err; 65730edc14bSKonrad Rzeszutek Wilk } 65830edc14bSKonrad Rzeszutek Wilk 659a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_be_watch(struct xenbus_watch *watch, 6605584ea25SJuergen Gross const char *path, const char *token) 66130edc14bSKonrad Rzeszutek Wilk { 662a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = 663a92336a1SKonrad Rzeszutek Wilk container_of(watch, struct xen_pcibk_device, be_watch); 66430edc14bSKonrad Rzeszutek Wilk 66530edc14bSKonrad Rzeszutek Wilk switch (xenbus_read_driver_state(pdev->xdev->nodename)) { 66630edc14bSKonrad Rzeszutek Wilk case XenbusStateInitWait: 667a92336a1SKonrad Rzeszutek Wilk xen_pcibk_setup_backend(pdev); 66830edc14bSKonrad Rzeszutek Wilk break; 66930edc14bSKonrad Rzeszutek Wilk 670c81d3d24SJan Beulich case XenbusStateInitialised: 671c81d3d24SJan Beulich /* 672c81d3d24SJan Beulich * We typically move to Initialised when the first device was 673c81d3d24SJan Beulich * added. Hence subsequent devices getting added may need 674c81d3d24SJan Beulich * reconfiguring. 675c81d3d24SJan Beulich */ 676c81d3d24SJan Beulich xen_pcibk_reconfigure(pdev, XenbusStateInitialised); 677c81d3d24SJan Beulich break; 678c81d3d24SJan Beulich 67930edc14bSKonrad Rzeszutek Wilk default: 68030edc14bSKonrad Rzeszutek Wilk break; 68130edc14bSKonrad Rzeszutek Wilk } 68230edc14bSKonrad Rzeszutek Wilk } 68330edc14bSKonrad Rzeszutek Wilk 684a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_xenbus_probe(struct xenbus_device *dev, 68530edc14bSKonrad Rzeszutek Wilk const struct xenbus_device_id *id) 68630edc14bSKonrad Rzeszutek Wilk { 68730edc14bSKonrad Rzeszutek Wilk int err = 0; 688a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = alloc_pdev(dev); 68930edc14bSKonrad Rzeszutek Wilk 69030edc14bSKonrad Rzeszutek Wilk if (pdev == NULL) { 69130edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 69230edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(dev, err, 693a92336a1SKonrad Rzeszutek Wilk "Error allocating xen_pcibk_device struct"); 69430edc14bSKonrad Rzeszutek Wilk goto out; 69530edc14bSKonrad Rzeszutek Wilk } 69630edc14bSKonrad Rzeszutek Wilk 69730edc14bSKonrad Rzeszutek Wilk /* wait for xend to configure us */ 69830edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(dev, XenbusStateInitWait); 69930edc14bSKonrad Rzeszutek Wilk if (err) 70030edc14bSKonrad Rzeszutek Wilk goto out; 70130edc14bSKonrad Rzeszutek Wilk 70230edc14bSKonrad Rzeszutek Wilk /* watch the backend node for backend configuration information */ 70330edc14bSKonrad Rzeszutek Wilk err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch, 7042e85d32bSSeongJae Park NULL, xen_pcibk_be_watch); 70530edc14bSKonrad Rzeszutek Wilk if (err) 70630edc14bSKonrad Rzeszutek Wilk goto out; 707494ef20dSKonrad Rzeszutek Wilk 70830edc14bSKonrad Rzeszutek Wilk pdev->be_watching = 1; 70930edc14bSKonrad Rzeszutek Wilk 71030edc14bSKonrad Rzeszutek Wilk /* We need to force a call to our callback here in case 71130edc14bSKonrad Rzeszutek Wilk * xend already configured us! 71230edc14bSKonrad Rzeszutek Wilk */ 713515762b9SHariprasad Kelam xen_pcibk_be_watch(&pdev->be_watch, NULL, NULL); 71430edc14bSKonrad Rzeszutek Wilk 71530edc14bSKonrad Rzeszutek Wilk out: 71630edc14bSKonrad Rzeszutek Wilk return err; 71730edc14bSKonrad Rzeszutek Wilk } 71830edc14bSKonrad Rzeszutek Wilk 719a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_xenbus_remove(struct xenbus_device *dev) 72030edc14bSKonrad Rzeszutek Wilk { 721a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev); 72230edc14bSKonrad Rzeszutek Wilk 72330edc14bSKonrad Rzeszutek Wilk if (pdev != NULL) 72430edc14bSKonrad Rzeszutek Wilk free_pdev(pdev); 72530edc14bSKonrad Rzeszutek Wilk 72630edc14bSKonrad Rzeszutek Wilk return 0; 72730edc14bSKonrad Rzeszutek Wilk } 72830edc14bSKonrad Rzeszutek Wilk 72973db144bSJan Beulich static const struct xenbus_device_id xen_pcibk_ids[] = { 73030edc14bSKonrad Rzeszutek Wilk {"pci"}, 73130edc14bSKonrad Rzeszutek Wilk {""}, 73230edc14bSKonrad Rzeszutek Wilk }; 73330edc14bSKonrad Rzeszutek Wilk 73495afae48SDavid Vrabel static struct xenbus_driver xen_pcibk_driver = { 73595afae48SDavid Vrabel .name = DRV_NAME, 73695afae48SDavid Vrabel .ids = xen_pcibk_ids, 737a92336a1SKonrad Rzeszutek Wilk .probe = xen_pcibk_xenbus_probe, 738a92336a1SKonrad Rzeszutek Wilk .remove = xen_pcibk_xenbus_remove, 739a92336a1SKonrad Rzeszutek Wilk .otherend_changed = xen_pcibk_frontend_changed, 74095afae48SDavid Vrabel }; 74130edc14bSKonrad Rzeszutek Wilk 742402c5e15SJan Beulich const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend; 7432ebdc426SKonrad Rzeszutek Wilk 744a92336a1SKonrad Rzeszutek Wilk int __init xen_pcibk_xenbus_register(void) 74530edc14bSKonrad Rzeszutek Wilk { 746*a67efff2SOleksandr Andrushchenko if (!xen_pcibk_pv_support()) 747*a67efff2SOleksandr Andrushchenko return 0; 748*a67efff2SOleksandr Andrushchenko 7492ebdc426SKonrad Rzeszutek Wilk xen_pcibk_backend = &xen_pcibk_vpci_backend; 7502ebdc426SKonrad Rzeszutek Wilk if (passthrough) 7512ebdc426SKonrad Rzeszutek Wilk xen_pcibk_backend = &xen_pcibk_passthrough_backend; 752283c0972SJoe Perches pr_info("backend is %s\n", xen_pcibk_backend->name); 75373db144bSJan Beulich return xenbus_register_backend(&xen_pcibk_driver); 75430edc14bSKonrad Rzeszutek Wilk } 75530edc14bSKonrad Rzeszutek Wilk 756a92336a1SKonrad Rzeszutek Wilk void __exit xen_pcibk_xenbus_unregister(void) 75730edc14bSKonrad Rzeszutek Wilk { 758*a67efff2SOleksandr Andrushchenko if (xen_pcibk_pv_support()) 75973db144bSJan Beulich xenbus_unregister_driver(&xen_pcibk_driver); 76030edc14bSKonrad Rzeszutek Wilk } 761