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> 176221a9b2SKonrad Rzeszutek Wilk #include <asm/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, 10830edc14bSKonrad Rzeszutek Wilk int 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, 11430edc14bSKonrad Rzeszutek Wilk "Attaching to frontend resources - gnt_ref=%d evtchn=%d\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 12630edc14bSKonrad Rzeszutek Wilk err = bind_interdomain_evtchn_to_irqhandler( 127a92336a1SKonrad Rzeszutek Wilk pdev->xdev->otherend_id, 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; 14530edc14bSKonrad Rzeszutek Wilk int gnt_ref, remote_evtchn; 14630edc14bSKonrad Rzeszutek Wilk char *magic = NULL; 14730edc14bSKonrad Rzeszutek Wilk 14830edc14bSKonrad Rzeszutek Wilk 149b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 15030edc14bSKonrad Rzeszutek Wilk /* Make sure we only do this setup once */ 15130edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->nodename) != 15230edc14bSKonrad Rzeszutek Wilk XenbusStateInitialised) 15330edc14bSKonrad Rzeszutek Wilk goto out; 15430edc14bSKonrad Rzeszutek Wilk 15530edc14bSKonrad Rzeszutek Wilk /* Wait for frontend to state that it has published the configuration */ 15630edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->otherend) != 15730edc14bSKonrad Rzeszutek Wilk XenbusStateInitialised) 15830edc14bSKonrad Rzeszutek Wilk goto out; 15930edc14bSKonrad Rzeszutek Wilk 16030edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Reading frontend config\n"); 16130edc14bSKonrad Rzeszutek Wilk 16230edc14bSKonrad Rzeszutek Wilk err = xenbus_gather(XBT_NIL, pdev->xdev->otherend, 16330edc14bSKonrad Rzeszutek Wilk "pci-op-ref", "%u", &gnt_ref, 16430edc14bSKonrad Rzeszutek Wilk "event-channel", "%u", &remote_evtchn, 16530edc14bSKonrad Rzeszutek Wilk "magic", NULL, &magic, NULL); 16630edc14bSKonrad Rzeszutek Wilk if (err) { 16730edc14bSKonrad Rzeszutek Wilk /* If configuration didn't get read correctly, wait longer */ 16830edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 16930edc14bSKonrad Rzeszutek Wilk "Error reading configuration from frontend"); 17030edc14bSKonrad Rzeszutek Wilk goto out; 17130edc14bSKonrad Rzeszutek Wilk } 17230edc14bSKonrad Rzeszutek Wilk 17330edc14bSKonrad Rzeszutek Wilk if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) { 17430edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, -EFAULT, 17530edc14bSKonrad Rzeszutek Wilk "version mismatch (%s/%s) with pcifront - " 176402c5e15SJan Beulich "halting " DRV_NAME, 17730edc14bSKonrad Rzeszutek Wilk magic, XEN_PCI_MAGIC); 1782ef76032SWei Yongjun err = -EFAULT; 17930edc14bSKonrad Rzeszutek Wilk goto out; 18030edc14bSKonrad Rzeszutek Wilk } 18130edc14bSKonrad Rzeszutek Wilk 182a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn); 18330edc14bSKonrad Rzeszutek Wilk if (err) 18430edc14bSKonrad Rzeszutek Wilk goto out; 18530edc14bSKonrad Rzeszutek Wilk 18630edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Connecting...\n"); 18730edc14bSKonrad Rzeszutek Wilk 18830edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); 18930edc14bSKonrad Rzeszutek Wilk if (err) 19030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 19130edc14bSKonrad Rzeszutek Wilk "Error switching to connected state!"); 19230edc14bSKonrad Rzeszutek Wilk 19330edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err); 19430edc14bSKonrad Rzeszutek Wilk out: 195b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 19630edc14bSKonrad Rzeszutek Wilk 19730edc14bSKonrad Rzeszutek Wilk kfree(magic); 19830edc14bSKonrad Rzeszutek Wilk 19930edc14bSKonrad Rzeszutek Wilk return err; 20030edc14bSKonrad Rzeszutek Wilk } 20130edc14bSKonrad Rzeszutek Wilk 202a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev, 20330edc14bSKonrad Rzeszutek Wilk unsigned int domain, unsigned int bus, 20430edc14bSKonrad Rzeszutek Wilk unsigned int devfn, unsigned int devid) 20530edc14bSKonrad Rzeszutek Wilk { 20630edc14bSKonrad Rzeszutek Wilk int err; 20730edc14bSKonrad Rzeszutek Wilk int len; 20830edc14bSKonrad Rzeszutek Wilk char str[64]; 20930edc14bSKonrad Rzeszutek Wilk 21030edc14bSKonrad Rzeszutek Wilk len = snprintf(str, sizeof(str), "vdev-%d", devid); 21130edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(str) - 1))) { 21230edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 21330edc14bSKonrad Rzeszutek Wilk goto out; 21430edc14bSKonrad Rzeszutek Wilk } 21530edc14bSKonrad Rzeszutek Wilk 216e4de866aSKonrad Rzeszutek Wilk /* Note: The PV protocol uses %02x, don't change it */ 21730edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, 21830edc14bSKonrad Rzeszutek Wilk "%04x:%02x:%02x.%02x", domain, bus, 21930edc14bSKonrad Rzeszutek Wilk PCI_SLOT(devfn), PCI_FUNC(devfn)); 22030edc14bSKonrad Rzeszutek Wilk 22130edc14bSKonrad Rzeszutek Wilk out: 22230edc14bSKonrad Rzeszutek Wilk return err; 22330edc14bSKonrad Rzeszutek Wilk } 22430edc14bSKonrad Rzeszutek Wilk 225a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_export_device(struct xen_pcibk_device *pdev, 22630edc14bSKonrad Rzeszutek Wilk int domain, int bus, int slot, int func, 22730edc14bSKonrad Rzeszutek Wilk int devid) 22830edc14bSKonrad Rzeszutek Wilk { 22930edc14bSKonrad Rzeszutek Wilk struct pci_dev *dev; 23030edc14bSKonrad Rzeszutek Wilk int err = 0; 23130edc14bSKonrad Rzeszutek Wilk 23230edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n", 23330edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 23430edc14bSKonrad Rzeszutek Wilk 23530edc14bSKonrad Rzeszutek Wilk dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func); 23630edc14bSKonrad Rzeszutek Wilk if (!dev) { 23730edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 23830edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 23930edc14bSKonrad Rzeszutek Wilk "Couldn't locate PCI device " 240e4de866aSKonrad Rzeszutek Wilk "(%04x:%02x:%02x.%d)! " 24130edc14bSKonrad Rzeszutek Wilk "perhaps already in-use?", 24230edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 24330edc14bSKonrad Rzeszutek Wilk goto out; 24430edc14bSKonrad Rzeszutek Wilk } 24530edc14bSKonrad Rzeszutek Wilk 246a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_add_pci_dev(pdev, dev, devid, 247a92336a1SKonrad Rzeszutek Wilk xen_pcibk_publish_pci_dev); 24830edc14bSKonrad Rzeszutek Wilk if (err) 24930edc14bSKonrad Rzeszutek Wilk goto out; 25030edc14bSKonrad Rzeszutek Wilk 25115390613SKonrad Rzeszutek Wilk dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id); 2526221a9b2SKonrad Rzeszutek Wilk if (xen_register_device_domain_owner(dev, 2536221a9b2SKonrad Rzeszutek Wilk pdev->xdev->otherend_id) != 0) { 2546c254de1SKonrad Rzeszutek Wilk dev_err(&dev->dev, "Stealing ownership from dom%d.\n", 2556c254de1SKonrad Rzeszutek Wilk xen_find_device_domain_owner(dev)); 2566221a9b2SKonrad Rzeszutek Wilk xen_unregister_device_domain_owner(dev); 2576221a9b2SKonrad Rzeszutek Wilk xen_register_device_domain_owner(dev, pdev->xdev->otherend_id); 2586221a9b2SKonrad Rzeszutek Wilk } 2596221a9b2SKonrad Rzeszutek Wilk 26030edc14bSKonrad Rzeszutek Wilk /* TODO: It'd be nice to export a bridge and have all of its children 26130edc14bSKonrad Rzeszutek Wilk * get exported with it. This may be best done in xend (which will 26230edc14bSKonrad Rzeszutek Wilk * have to calculate resource usage anyway) but we probably want to 26330edc14bSKonrad Rzeszutek Wilk * put something in here to ensure that if a bridge gets given to a 26430edc14bSKonrad Rzeszutek Wilk * driver domain, that all devices under that bridge are not given 26530edc14bSKonrad Rzeszutek Wilk * to other driver domains (as he who controls the bridge can disable 26630edc14bSKonrad Rzeszutek Wilk * it and stop the other devices from working). 26730edc14bSKonrad Rzeszutek Wilk */ 26830edc14bSKonrad Rzeszutek Wilk out: 26930edc14bSKonrad Rzeszutek Wilk return err; 27030edc14bSKonrad Rzeszutek Wilk } 27130edc14bSKonrad Rzeszutek Wilk 272a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev, 27330edc14bSKonrad Rzeszutek Wilk int domain, int bus, int slot, int func) 27430edc14bSKonrad Rzeszutek Wilk { 27530edc14bSKonrad Rzeszutek Wilk int err = 0; 27630edc14bSKonrad Rzeszutek Wilk struct pci_dev *dev; 27730edc14bSKonrad Rzeszutek Wilk 27830edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n", 27930edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 28030edc14bSKonrad Rzeszutek Wilk 281a92336a1SKonrad Rzeszutek Wilk dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func)); 28230edc14bSKonrad Rzeszutek Wilk if (!dev) { 28330edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 28430edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device " 285e4de866aSKonrad Rzeszutek Wilk "(%04x:%02x:%02x.%d)! not owned by this domain\n", 28630edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 28730edc14bSKonrad Rzeszutek Wilk goto out; 28830edc14bSKonrad Rzeszutek Wilk } 28930edc14bSKonrad Rzeszutek Wilk 2906221a9b2SKonrad Rzeszutek Wilk dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id); 2916221a9b2SKonrad Rzeszutek Wilk xen_unregister_device_domain_owner(dev); 2926221a9b2SKonrad Rzeszutek Wilk 2938be9df6dSKonrad Rzeszutek Wilk /* N.B. This ends up calling pcistub_put_pci_dev which ends up 2948be9df6dSKonrad Rzeszutek Wilk * doing the FLR. */ 295e8801a74SKonrad Rzeszutek Wilk xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */); 29630edc14bSKonrad Rzeszutek Wilk 29730edc14bSKonrad Rzeszutek Wilk out: 29830edc14bSKonrad Rzeszutek Wilk return err; 29930edc14bSKonrad Rzeszutek Wilk } 30030edc14bSKonrad Rzeszutek Wilk 301a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev, 30230edc14bSKonrad Rzeszutek Wilk unsigned int domain, unsigned int bus) 30330edc14bSKonrad Rzeszutek Wilk { 30430edc14bSKonrad Rzeszutek Wilk unsigned int d, b; 30530edc14bSKonrad Rzeszutek Wilk int i, root_num, len, err; 30630edc14bSKonrad Rzeszutek Wilk char str[64]; 30730edc14bSKonrad Rzeszutek Wilk 30830edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n"); 30930edc14bSKonrad Rzeszutek Wilk 31030edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 31130edc14bSKonrad Rzeszutek Wilk "root_num", "%d", &root_num); 31230edc14bSKonrad Rzeszutek Wilk if (err == 0 || err == -ENOENT) 31330edc14bSKonrad Rzeszutek Wilk root_num = 0; 31430edc14bSKonrad Rzeszutek Wilk else if (err < 0) 31530edc14bSKonrad Rzeszutek Wilk goto out; 31630edc14bSKonrad Rzeszutek Wilk 31730edc14bSKonrad Rzeszutek Wilk /* Verify that we haven't already published this pci root */ 31830edc14bSKonrad Rzeszutek Wilk for (i = 0; i < root_num; i++) { 31930edc14bSKonrad Rzeszutek Wilk len = snprintf(str, sizeof(str), "root-%d", i); 32030edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(str) - 1))) { 32130edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 32230edc14bSKonrad Rzeszutek Wilk goto out; 32330edc14bSKonrad Rzeszutek Wilk } 32430edc14bSKonrad Rzeszutek Wilk 32530edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 32630edc14bSKonrad Rzeszutek Wilk str, "%x:%x", &d, &b); 32730edc14bSKonrad Rzeszutek Wilk if (err < 0) 32830edc14bSKonrad Rzeszutek Wilk goto out; 32930edc14bSKonrad Rzeszutek Wilk if (err != 2) { 33030edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 33130edc14bSKonrad Rzeszutek Wilk goto out; 33230edc14bSKonrad Rzeszutek Wilk } 33330edc14bSKonrad Rzeszutek Wilk 33430edc14bSKonrad Rzeszutek Wilk if (d == domain && b == bus) { 33530edc14bSKonrad Rzeszutek Wilk err = 0; 33630edc14bSKonrad Rzeszutek Wilk goto out; 33730edc14bSKonrad Rzeszutek Wilk } 33830edc14bSKonrad Rzeszutek Wilk } 33930edc14bSKonrad Rzeszutek Wilk 34030edc14bSKonrad Rzeszutek Wilk len = snprintf(str, sizeof(str), "root-%d", root_num); 34130edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(str) - 1))) { 34230edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 34330edc14bSKonrad Rzeszutek Wilk goto out; 34430edc14bSKonrad Rzeszutek Wilk } 34530edc14bSKonrad Rzeszutek Wilk 34630edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n", 34730edc14bSKonrad Rzeszutek Wilk root_num, domain, bus); 34830edc14bSKonrad Rzeszutek Wilk 34930edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, 35030edc14bSKonrad Rzeszutek Wilk "%04x:%02x", domain, bus); 35130edc14bSKonrad Rzeszutek Wilk if (err) 35230edc14bSKonrad Rzeszutek Wilk goto out; 35330edc14bSKonrad Rzeszutek Wilk 35430edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, 35530edc14bSKonrad Rzeszutek Wilk "root_num", "%d", (root_num + 1)); 35630edc14bSKonrad Rzeszutek Wilk 35730edc14bSKonrad Rzeszutek Wilk out: 35830edc14bSKonrad Rzeszutek Wilk return err; 35930edc14bSKonrad Rzeszutek Wilk } 36030edc14bSKonrad Rzeszutek Wilk 361a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev) 36230edc14bSKonrad Rzeszutek Wilk { 36330edc14bSKonrad Rzeszutek Wilk int err = 0; 36430edc14bSKonrad Rzeszutek Wilk int num_devs; 36530edc14bSKonrad Rzeszutek Wilk int domain, bus, slot, func; 3664e81f1caSJuergen Gross unsigned int substate; 36730edc14bSKonrad Rzeszutek Wilk int i, len; 36830edc14bSKonrad Rzeszutek Wilk char state_str[64]; 36930edc14bSKonrad Rzeszutek Wilk char dev_str[64]; 37030edc14bSKonrad Rzeszutek Wilk 37130edc14bSKonrad Rzeszutek Wilk 37230edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n"); 37330edc14bSKonrad Rzeszutek Wilk 374b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 37530edc14bSKonrad Rzeszutek Wilk /* Make sure we only reconfigure once */ 37630edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->nodename) != 37730edc14bSKonrad Rzeszutek Wilk XenbusStateReconfiguring) 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 50230edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured); 50330edc14bSKonrad Rzeszutek Wilk if (err) { 50430edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 50530edc14bSKonrad Rzeszutek Wilk "Error switching to reconfigured state!"); 50630edc14bSKonrad Rzeszutek Wilk goto out; 50730edc14bSKonrad Rzeszutek Wilk } 50830edc14bSKonrad Rzeszutek Wilk 50930edc14bSKonrad Rzeszutek Wilk out: 510b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 51130edc14bSKonrad Rzeszutek Wilk return 0; 51230edc14bSKonrad Rzeszutek Wilk } 51330edc14bSKonrad Rzeszutek Wilk 514a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_frontend_changed(struct xenbus_device *xdev, 51530edc14bSKonrad Rzeszutek Wilk enum xenbus_state fe_state) 51630edc14bSKonrad Rzeszutek Wilk { 517a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev); 51830edc14bSKonrad Rzeszutek Wilk 51930edc14bSKonrad Rzeszutek Wilk dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state); 52030edc14bSKonrad Rzeszutek Wilk 52130edc14bSKonrad Rzeszutek Wilk switch (fe_state) { 52230edc14bSKonrad Rzeszutek Wilk case XenbusStateInitialised: 523a92336a1SKonrad Rzeszutek Wilk xen_pcibk_attach(pdev); 52430edc14bSKonrad Rzeszutek Wilk break; 52530edc14bSKonrad Rzeszutek Wilk 52630edc14bSKonrad Rzeszutek Wilk case XenbusStateReconfiguring: 527a92336a1SKonrad Rzeszutek Wilk xen_pcibk_reconfigure(pdev); 52830edc14bSKonrad Rzeszutek Wilk break; 52930edc14bSKonrad Rzeszutek Wilk 53030edc14bSKonrad Rzeszutek Wilk case XenbusStateConnected: 53130edc14bSKonrad Rzeszutek Wilk /* pcifront switched its state from reconfiguring to connected. 53230edc14bSKonrad Rzeszutek Wilk * Then switch to connected state. 53330edc14bSKonrad Rzeszutek Wilk */ 53430edc14bSKonrad Rzeszutek Wilk xenbus_switch_state(xdev, XenbusStateConnected); 53530edc14bSKonrad Rzeszutek Wilk break; 53630edc14bSKonrad Rzeszutek Wilk 53730edc14bSKonrad Rzeszutek Wilk case XenbusStateClosing: 538a92336a1SKonrad Rzeszutek Wilk xen_pcibk_disconnect(pdev); 53930edc14bSKonrad Rzeszutek Wilk xenbus_switch_state(xdev, XenbusStateClosing); 54030edc14bSKonrad Rzeszutek Wilk break; 54130edc14bSKonrad Rzeszutek Wilk 54230edc14bSKonrad Rzeszutek Wilk case XenbusStateClosed: 543a92336a1SKonrad Rzeszutek Wilk xen_pcibk_disconnect(pdev); 54430edc14bSKonrad Rzeszutek Wilk xenbus_switch_state(xdev, XenbusStateClosed); 54530edc14bSKonrad Rzeszutek Wilk if (xenbus_dev_is_online(xdev)) 54630edc14bSKonrad Rzeszutek Wilk break; 547c9f19b67SGustavo A. R. Silva /* fall through - if not online */ 54830edc14bSKonrad Rzeszutek Wilk case XenbusStateUnknown: 54930edc14bSKonrad Rzeszutek Wilk dev_dbg(&xdev->dev, "frontend is gone! unregister device\n"); 55030edc14bSKonrad Rzeszutek Wilk device_unregister(&xdev->dev); 55130edc14bSKonrad Rzeszutek Wilk break; 55230edc14bSKonrad Rzeszutek Wilk 55330edc14bSKonrad Rzeszutek Wilk default: 55430edc14bSKonrad Rzeszutek Wilk break; 55530edc14bSKonrad Rzeszutek Wilk } 55630edc14bSKonrad Rzeszutek Wilk } 55730edc14bSKonrad Rzeszutek Wilk 558a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev) 55930edc14bSKonrad Rzeszutek Wilk { 56030edc14bSKonrad Rzeszutek Wilk /* Get configuration from xend (if available now) */ 56130edc14bSKonrad Rzeszutek Wilk int domain, bus, slot, func; 56230edc14bSKonrad Rzeszutek Wilk int err = 0; 56330edc14bSKonrad Rzeszutek Wilk int i, num_devs; 56430edc14bSKonrad Rzeszutek Wilk char dev_str[64]; 56530edc14bSKonrad Rzeszutek Wilk char state_str[64]; 56630edc14bSKonrad Rzeszutek Wilk 567b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 56830edc14bSKonrad Rzeszutek Wilk /* It's possible we could get the call to setup twice, so make sure 56930edc14bSKonrad Rzeszutek Wilk * we're not already connected. 57030edc14bSKonrad Rzeszutek Wilk */ 57130edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->nodename) != 57230edc14bSKonrad Rzeszutek Wilk XenbusStateInitWait) 57330edc14bSKonrad Rzeszutek Wilk goto out; 57430edc14bSKonrad Rzeszutek Wilk 57530edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "getting be setup\n"); 57630edc14bSKonrad Rzeszutek Wilk 57730edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", 57830edc14bSKonrad Rzeszutek Wilk &num_devs); 57930edc14bSKonrad Rzeszutek Wilk if (err != 1) { 58030edc14bSKonrad Rzeszutek Wilk if (err >= 0) 58130edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 58230edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 58330edc14bSKonrad Rzeszutek Wilk "Error reading number of devices"); 58430edc14bSKonrad Rzeszutek Wilk goto out; 58530edc14bSKonrad Rzeszutek Wilk } 58630edc14bSKonrad Rzeszutek Wilk 58730edc14bSKonrad Rzeszutek Wilk for (i = 0; i < num_devs; i++) { 58830edc14bSKonrad Rzeszutek Wilk int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); 58930edc14bSKonrad Rzeszutek Wilk if (unlikely(l >= (sizeof(dev_str) - 1))) { 59030edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 59130edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 59230edc14bSKonrad Rzeszutek Wilk "String overflow while reading " 59330edc14bSKonrad Rzeszutek Wilk "configuration"); 59430edc14bSKonrad Rzeszutek Wilk goto out; 59530edc14bSKonrad Rzeszutek Wilk } 59630edc14bSKonrad Rzeszutek Wilk 59730edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str, 59830edc14bSKonrad Rzeszutek Wilk "%x:%x:%x.%x", &domain, &bus, &slot, &func); 59930edc14bSKonrad Rzeszutek Wilk if (err < 0) { 60030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 60130edc14bSKonrad Rzeszutek Wilk "Error reading device configuration"); 60230edc14bSKonrad Rzeszutek Wilk goto out; 60330edc14bSKonrad Rzeszutek Wilk } 60430edc14bSKonrad Rzeszutek Wilk if (err != 4) { 60530edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 60630edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 60730edc14bSKonrad Rzeszutek Wilk "Error parsing pci device " 60830edc14bSKonrad Rzeszutek Wilk "configuration"); 60930edc14bSKonrad Rzeszutek Wilk goto out; 61030edc14bSKonrad Rzeszutek Wilk } 61130edc14bSKonrad Rzeszutek Wilk 612a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i); 61330edc14bSKonrad Rzeszutek Wilk if (err) 61430edc14bSKonrad Rzeszutek Wilk goto out; 61530edc14bSKonrad Rzeszutek Wilk 61630edc14bSKonrad Rzeszutek Wilk /* Switch substate of this device. */ 61730edc14bSKonrad Rzeszutek Wilk l = snprintf(state_str, sizeof(state_str), "state-%d", i); 61830edc14bSKonrad Rzeszutek Wilk if (unlikely(l >= (sizeof(state_str) - 1))) { 61930edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 62030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 62130edc14bSKonrad Rzeszutek Wilk "String overflow while reading " 62230edc14bSKonrad Rzeszutek Wilk "configuration"); 62330edc14bSKonrad Rzeszutek Wilk goto out; 62430edc14bSKonrad Rzeszutek Wilk } 62530edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str, 62630edc14bSKonrad Rzeszutek Wilk "%d", XenbusStateInitialised); 62730edc14bSKonrad Rzeszutek Wilk if (err) { 62830edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, "Error switching " 62930edc14bSKonrad Rzeszutek Wilk "substate of dev-%d\n", i); 63030edc14bSKonrad Rzeszutek Wilk goto out; 63130edc14bSKonrad Rzeszutek Wilk } 63230edc14bSKonrad Rzeszutek Wilk } 63330edc14bSKonrad Rzeszutek Wilk 634a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root); 63530edc14bSKonrad Rzeszutek Wilk if (err) { 63630edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 63730edc14bSKonrad Rzeszutek Wilk "Error while publish PCI root buses " 63830edc14bSKonrad Rzeszutek Wilk "for frontend"); 63930edc14bSKonrad Rzeszutek Wilk goto out; 64030edc14bSKonrad Rzeszutek Wilk } 64130edc14bSKonrad Rzeszutek Wilk 64230edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised); 64330edc14bSKonrad Rzeszutek Wilk if (err) 64430edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 64530edc14bSKonrad Rzeszutek Wilk "Error switching to initialised state!"); 64630edc14bSKonrad Rzeszutek Wilk 64730edc14bSKonrad Rzeszutek Wilk out: 648b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 64930edc14bSKonrad Rzeszutek Wilk if (!err) 65030edc14bSKonrad Rzeszutek Wilk /* see if pcifront is already configured (if not, we'll wait) */ 651a92336a1SKonrad Rzeszutek Wilk xen_pcibk_attach(pdev); 65230edc14bSKonrad Rzeszutek Wilk return err; 65330edc14bSKonrad Rzeszutek Wilk } 65430edc14bSKonrad Rzeszutek Wilk 655a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_be_watch(struct xenbus_watch *watch, 6565584ea25SJuergen Gross const char *path, const char *token) 65730edc14bSKonrad Rzeszutek Wilk { 658a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = 659a92336a1SKonrad Rzeszutek Wilk container_of(watch, struct xen_pcibk_device, be_watch); 66030edc14bSKonrad Rzeszutek Wilk 66130edc14bSKonrad Rzeszutek Wilk switch (xenbus_read_driver_state(pdev->xdev->nodename)) { 66230edc14bSKonrad Rzeszutek Wilk case XenbusStateInitWait: 663a92336a1SKonrad Rzeszutek Wilk xen_pcibk_setup_backend(pdev); 66430edc14bSKonrad Rzeszutek Wilk break; 66530edc14bSKonrad Rzeszutek Wilk 66630edc14bSKonrad Rzeszutek Wilk default: 66730edc14bSKonrad Rzeszutek Wilk break; 66830edc14bSKonrad Rzeszutek Wilk } 66930edc14bSKonrad Rzeszutek Wilk } 67030edc14bSKonrad Rzeszutek Wilk 671a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_xenbus_probe(struct xenbus_device *dev, 67230edc14bSKonrad Rzeszutek Wilk const struct xenbus_device_id *id) 67330edc14bSKonrad Rzeszutek Wilk { 67430edc14bSKonrad Rzeszutek Wilk int err = 0; 675a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = alloc_pdev(dev); 67630edc14bSKonrad Rzeszutek Wilk 67730edc14bSKonrad Rzeszutek Wilk if (pdev == NULL) { 67830edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 67930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(dev, err, 680a92336a1SKonrad Rzeszutek Wilk "Error allocating xen_pcibk_device struct"); 68130edc14bSKonrad Rzeszutek Wilk goto out; 68230edc14bSKonrad Rzeszutek Wilk } 68330edc14bSKonrad Rzeszutek Wilk 68430edc14bSKonrad Rzeszutek Wilk /* wait for xend to configure us */ 68530edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(dev, XenbusStateInitWait); 68630edc14bSKonrad Rzeszutek Wilk if (err) 68730edc14bSKonrad Rzeszutek Wilk goto out; 68830edc14bSKonrad Rzeszutek Wilk 68930edc14bSKonrad Rzeszutek Wilk /* watch the backend node for backend configuration information */ 69030edc14bSKonrad Rzeszutek Wilk err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch, 691a92336a1SKonrad Rzeszutek Wilk xen_pcibk_be_watch); 69230edc14bSKonrad Rzeszutek Wilk if (err) 69330edc14bSKonrad Rzeszutek Wilk goto out; 694494ef20dSKonrad Rzeszutek Wilk 69530edc14bSKonrad Rzeszutek Wilk pdev->be_watching = 1; 69630edc14bSKonrad Rzeszutek Wilk 69730edc14bSKonrad Rzeszutek Wilk /* We need to force a call to our callback here in case 69830edc14bSKonrad Rzeszutek Wilk * xend already configured us! 69930edc14bSKonrad Rzeszutek Wilk */ 700515762b9SHariprasad Kelam xen_pcibk_be_watch(&pdev->be_watch, NULL, NULL); 70130edc14bSKonrad Rzeszutek Wilk 70230edc14bSKonrad Rzeszutek Wilk out: 70330edc14bSKonrad Rzeszutek Wilk return err; 70430edc14bSKonrad Rzeszutek Wilk } 70530edc14bSKonrad Rzeszutek Wilk 706a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_xenbus_remove(struct xenbus_device *dev) 70730edc14bSKonrad Rzeszutek Wilk { 708a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev); 70930edc14bSKonrad Rzeszutek Wilk 71030edc14bSKonrad Rzeszutek Wilk if (pdev != NULL) 71130edc14bSKonrad Rzeszutek Wilk free_pdev(pdev); 71230edc14bSKonrad Rzeszutek Wilk 71330edc14bSKonrad Rzeszutek Wilk return 0; 71430edc14bSKonrad Rzeszutek Wilk } 71530edc14bSKonrad Rzeszutek Wilk 71673db144bSJan Beulich static const struct xenbus_device_id xen_pcibk_ids[] = { 71730edc14bSKonrad Rzeszutek Wilk {"pci"}, 71830edc14bSKonrad Rzeszutek Wilk {""}, 71930edc14bSKonrad Rzeszutek Wilk }; 72030edc14bSKonrad Rzeszutek Wilk 72195afae48SDavid Vrabel static struct xenbus_driver xen_pcibk_driver = { 72295afae48SDavid Vrabel .name = DRV_NAME, 72395afae48SDavid Vrabel .ids = xen_pcibk_ids, 724a92336a1SKonrad Rzeszutek Wilk .probe = xen_pcibk_xenbus_probe, 725a92336a1SKonrad Rzeszutek Wilk .remove = xen_pcibk_xenbus_remove, 726a92336a1SKonrad Rzeszutek Wilk .otherend_changed = xen_pcibk_frontend_changed, 72795afae48SDavid Vrabel }; 72830edc14bSKonrad Rzeszutek Wilk 729402c5e15SJan Beulich const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend; 7302ebdc426SKonrad Rzeszutek Wilk 731a92336a1SKonrad Rzeszutek Wilk int __init xen_pcibk_xenbus_register(void) 73230edc14bSKonrad Rzeszutek Wilk { 7332ebdc426SKonrad Rzeszutek Wilk xen_pcibk_backend = &xen_pcibk_vpci_backend; 7342ebdc426SKonrad Rzeszutek Wilk if (passthrough) 7352ebdc426SKonrad Rzeszutek Wilk xen_pcibk_backend = &xen_pcibk_passthrough_backend; 736283c0972SJoe Perches pr_info("backend is %s\n", xen_pcibk_backend->name); 73773db144bSJan Beulich return xenbus_register_backend(&xen_pcibk_driver); 73830edc14bSKonrad Rzeszutek Wilk } 73930edc14bSKonrad Rzeszutek Wilk 740a92336a1SKonrad Rzeszutek Wilk void __exit xen_pcibk_xenbus_unregister(void) 74130edc14bSKonrad Rzeszutek Wilk { 74273db144bSJan Beulich xenbus_unregister_driver(&xen_pcibk_driver); 74330edc14bSKonrad Rzeszutek Wilk } 744