130edc14bSKonrad Rzeszutek Wilk /* 230edc14bSKonrad Rzeszutek Wilk * PCI Backend Xenbus Setup - handles setup with frontend and xend 330edc14bSKonrad Rzeszutek Wilk * 430edc14bSKonrad Rzeszutek Wilk * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 530edc14bSKonrad Rzeszutek Wilk */ 6283c0972SJoe Perches 7283c0972SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 8283c0972SJoe Perches 930edc14bSKonrad Rzeszutek Wilk #include <linux/module.h> 1030edc14bSKonrad Rzeszutek Wilk #include <linux/init.h> 1130edc14bSKonrad Rzeszutek Wilk #include <linux/list.h> 1230edc14bSKonrad Rzeszutek Wilk #include <linux/vmalloc.h> 1330edc14bSKonrad Rzeszutek Wilk #include <linux/workqueue.h> 1430edc14bSKonrad Rzeszutek Wilk #include <xen/xenbus.h> 1530edc14bSKonrad Rzeszutek Wilk #include <xen/events.h> 166221a9b2SKonrad Rzeszutek Wilk #include <asm/xen/pci.h> 1730edc14bSKonrad Rzeszutek Wilk #include "pciback.h" 1830edc14bSKonrad Rzeszutek Wilk 1930edc14bSKonrad Rzeszutek Wilk #define INVALID_EVTCHN_IRQ (-1) 20a92336a1SKonrad Rzeszutek Wilk struct workqueue_struct *xen_pcibk_wq; 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 dev_set_drvdata(&xdev->dev, pdev); 4830edc14bSKonrad Rzeszutek Wilk 49b1766b62SKonrad Rzeszutek Wilk mutex_init(&pdev->dev_lock); 5030edc14bSKonrad Rzeszutek Wilk 5130edc14bSKonrad Rzeszutek Wilk pdev->sh_info = NULL; 5230edc14bSKonrad Rzeszutek Wilk pdev->evtchn_irq = INVALID_EVTCHN_IRQ; 5330edc14bSKonrad Rzeszutek Wilk pdev->be_watching = 0; 5430edc14bSKonrad Rzeszutek Wilk 55a92336a1SKonrad Rzeszutek Wilk INIT_WORK(&pdev->op_work, xen_pcibk_do_op); 5630edc14bSKonrad Rzeszutek Wilk 57a92336a1SKonrad Rzeszutek Wilk if (xen_pcibk_init_devices(pdev)) { 5830edc14bSKonrad Rzeszutek Wilk kfree(pdev); 5930edc14bSKonrad Rzeszutek Wilk pdev = NULL; 6030edc14bSKonrad Rzeszutek Wilk } 6130edc14bSKonrad Rzeszutek Wilk out: 6230edc14bSKonrad Rzeszutek Wilk return pdev; 6330edc14bSKonrad Rzeszutek Wilk } 6430edc14bSKonrad Rzeszutek Wilk 65a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_disconnect(struct xen_pcibk_device *pdev) 6630edc14bSKonrad Rzeszutek Wilk { 67b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 6830edc14bSKonrad Rzeszutek Wilk /* Ensure the guest can't trigger our handler before removing devices */ 6930edc14bSKonrad Rzeszutek Wilk if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) { 7030edc14bSKonrad Rzeszutek Wilk unbind_from_irqhandler(pdev->evtchn_irq, pdev); 7130edc14bSKonrad Rzeszutek Wilk pdev->evtchn_irq = INVALID_EVTCHN_IRQ; 7230edc14bSKonrad Rzeszutek Wilk } 7330edc14bSKonrad Rzeszutek Wilk 7430edc14bSKonrad Rzeszutek Wilk /* If the driver domain started an op, make sure we complete it 7530edc14bSKonrad Rzeszutek Wilk * before releasing the shared memory */ 76494ef20dSKonrad Rzeszutek Wilk 77494ef20dSKonrad Rzeszutek Wilk /* Note, the workqueue does not use spinlocks at all.*/ 78a92336a1SKonrad Rzeszutek Wilk flush_workqueue(xen_pcibk_wq); 7930edc14bSKonrad Rzeszutek Wilk 8030edc14bSKonrad Rzeszutek Wilk if (pdev->sh_info != NULL) { 8130edc14bSKonrad Rzeszutek Wilk xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info); 8230edc14bSKonrad Rzeszutek Wilk pdev->sh_info = NULL; 8330edc14bSKonrad Rzeszutek Wilk } 84b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 8530edc14bSKonrad Rzeszutek Wilk } 8630edc14bSKonrad Rzeszutek Wilk 87a92336a1SKonrad Rzeszutek Wilk static void free_pdev(struct xen_pcibk_device *pdev) 8830edc14bSKonrad Rzeszutek Wilk { 89494ef20dSKonrad Rzeszutek Wilk if (pdev->be_watching) { 9030edc14bSKonrad Rzeszutek Wilk unregister_xenbus_watch(&pdev->be_watch); 91494ef20dSKonrad Rzeszutek Wilk pdev->be_watching = 0; 92494ef20dSKonrad Rzeszutek Wilk } 9330edc14bSKonrad Rzeszutek Wilk 94a92336a1SKonrad Rzeszutek Wilk xen_pcibk_disconnect(pdev); 9530edc14bSKonrad Rzeszutek Wilk 968be9df6dSKonrad Rzeszutek Wilk /* N.B. This calls pcistub_put_pci_dev which does the FLR on all 978be9df6dSKonrad Rzeszutek Wilk * of the PCIe devices. */ 98a92336a1SKonrad Rzeszutek Wilk xen_pcibk_release_devices(pdev); 9930edc14bSKonrad Rzeszutek Wilk 10030edc14bSKonrad Rzeszutek Wilk dev_set_drvdata(&pdev->xdev->dev, NULL); 10130edc14bSKonrad Rzeszutek Wilk pdev->xdev = NULL; 10230edc14bSKonrad Rzeszutek Wilk 10330edc14bSKonrad Rzeszutek Wilk kfree(pdev); 10430edc14bSKonrad Rzeszutek Wilk } 10530edc14bSKonrad Rzeszutek Wilk 106a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref, 10730edc14bSKonrad Rzeszutek Wilk int remote_evtchn) 10830edc14bSKonrad Rzeszutek Wilk { 10930edc14bSKonrad Rzeszutek Wilk int err = 0; 11030edc14bSKonrad Rzeszutek Wilk void *vaddr; 11130edc14bSKonrad Rzeszutek Wilk 11230edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, 11330edc14bSKonrad Rzeszutek Wilk "Attaching to frontend resources - gnt_ref=%d evtchn=%d\n", 11430edc14bSKonrad Rzeszutek Wilk gnt_ref, remote_evtchn); 11530edc14bSKonrad Rzeszutek Wilk 116ccc9d90aSWei Liu err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr); 11730edc14bSKonrad Rzeszutek Wilk if (err < 0) { 11830edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 11930edc14bSKonrad Rzeszutek Wilk "Error mapping other domain page in ours."); 12030edc14bSKonrad Rzeszutek Wilk goto out; 12130edc14bSKonrad Rzeszutek Wilk } 122494ef20dSKonrad Rzeszutek Wilk 12330edc14bSKonrad Rzeszutek Wilk pdev->sh_info = vaddr; 12430edc14bSKonrad Rzeszutek Wilk 12530edc14bSKonrad Rzeszutek Wilk err = bind_interdomain_evtchn_to_irqhandler( 126a92336a1SKonrad Rzeszutek Wilk pdev->xdev->otherend_id, remote_evtchn, xen_pcibk_handle_event, 127a92336a1SKonrad Rzeszutek Wilk 0, DRV_NAME, pdev); 12830edc14bSKonrad Rzeszutek Wilk if (err < 0) { 12930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 13030edc14bSKonrad Rzeszutek Wilk "Error binding event channel to IRQ"); 13130edc14bSKonrad Rzeszutek Wilk goto out; 13230edc14bSKonrad Rzeszutek Wilk } 13330edc14bSKonrad Rzeszutek Wilk pdev->evtchn_irq = err; 13430edc14bSKonrad Rzeszutek Wilk err = 0; 13530edc14bSKonrad Rzeszutek Wilk 13630edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Attached!\n"); 13730edc14bSKonrad Rzeszutek Wilk out: 13830edc14bSKonrad Rzeszutek Wilk return err; 13930edc14bSKonrad Rzeszutek Wilk } 14030edc14bSKonrad Rzeszutek Wilk 141a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_attach(struct xen_pcibk_device *pdev) 14230edc14bSKonrad Rzeszutek Wilk { 14330edc14bSKonrad Rzeszutek Wilk int err = 0; 14430edc14bSKonrad Rzeszutek Wilk int gnt_ref, remote_evtchn; 14530edc14bSKonrad Rzeszutek Wilk char *magic = NULL; 14630edc14bSKonrad Rzeszutek Wilk 14730edc14bSKonrad Rzeszutek Wilk 148b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 14930edc14bSKonrad Rzeszutek Wilk /* Make sure we only do this setup once */ 15030edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->nodename) != 15130edc14bSKonrad Rzeszutek Wilk XenbusStateInitialised) 15230edc14bSKonrad Rzeszutek Wilk goto out; 15330edc14bSKonrad Rzeszutek Wilk 15430edc14bSKonrad Rzeszutek Wilk /* Wait for frontend to state that it has published the configuration */ 15530edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->otherend) != 15630edc14bSKonrad Rzeszutek Wilk XenbusStateInitialised) 15730edc14bSKonrad Rzeszutek Wilk goto out; 15830edc14bSKonrad Rzeszutek Wilk 15930edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Reading frontend config\n"); 16030edc14bSKonrad Rzeszutek Wilk 16130edc14bSKonrad Rzeszutek Wilk err = xenbus_gather(XBT_NIL, pdev->xdev->otherend, 16230edc14bSKonrad Rzeszutek Wilk "pci-op-ref", "%u", &gnt_ref, 16330edc14bSKonrad Rzeszutek Wilk "event-channel", "%u", &remote_evtchn, 16430edc14bSKonrad Rzeszutek Wilk "magic", NULL, &magic, NULL); 16530edc14bSKonrad Rzeszutek Wilk if (err) { 16630edc14bSKonrad Rzeszutek Wilk /* If configuration didn't get read correctly, wait longer */ 16730edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 16830edc14bSKonrad Rzeszutek Wilk "Error reading configuration from frontend"); 16930edc14bSKonrad Rzeszutek Wilk goto out; 17030edc14bSKonrad Rzeszutek Wilk } 17130edc14bSKonrad Rzeszutek Wilk 17230edc14bSKonrad Rzeszutek Wilk if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) { 17330edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, -EFAULT, 17430edc14bSKonrad Rzeszutek Wilk "version mismatch (%s/%s) with pcifront - " 175402c5e15SJan Beulich "halting " DRV_NAME, 17630edc14bSKonrad Rzeszutek Wilk magic, XEN_PCI_MAGIC); 1772ef76032SWei Yongjun err = -EFAULT; 17830edc14bSKonrad Rzeszutek Wilk goto out; 17930edc14bSKonrad Rzeszutek Wilk } 18030edc14bSKonrad Rzeszutek Wilk 181a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn); 18230edc14bSKonrad Rzeszutek Wilk if (err) 18330edc14bSKonrad Rzeszutek Wilk goto out; 18430edc14bSKonrad Rzeszutek Wilk 18530edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Connecting...\n"); 18630edc14bSKonrad Rzeszutek Wilk 18730edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); 18830edc14bSKonrad Rzeszutek Wilk if (err) 18930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 19030edc14bSKonrad Rzeszutek Wilk "Error switching to connected state!"); 19130edc14bSKonrad Rzeszutek Wilk 19230edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err); 19330edc14bSKonrad Rzeszutek Wilk out: 194b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 19530edc14bSKonrad Rzeszutek Wilk 19630edc14bSKonrad Rzeszutek Wilk kfree(magic); 19730edc14bSKonrad Rzeszutek Wilk 19830edc14bSKonrad Rzeszutek Wilk return err; 19930edc14bSKonrad Rzeszutek Wilk } 20030edc14bSKonrad Rzeszutek Wilk 201a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev, 20230edc14bSKonrad Rzeszutek Wilk unsigned int domain, unsigned int bus, 20330edc14bSKonrad Rzeszutek Wilk unsigned int devfn, unsigned int devid) 20430edc14bSKonrad Rzeszutek Wilk { 20530edc14bSKonrad Rzeszutek Wilk int err; 20630edc14bSKonrad Rzeszutek Wilk int len; 20730edc14bSKonrad Rzeszutek Wilk char str[64]; 20830edc14bSKonrad Rzeszutek Wilk 20930edc14bSKonrad Rzeszutek Wilk len = snprintf(str, sizeof(str), "vdev-%d", devid); 21030edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(str) - 1))) { 21130edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 21230edc14bSKonrad Rzeszutek Wilk goto out; 21330edc14bSKonrad Rzeszutek Wilk } 21430edc14bSKonrad Rzeszutek Wilk 215e4de866aSKonrad Rzeszutek Wilk /* Note: The PV protocol uses %02x, don't change it */ 21630edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, 21730edc14bSKonrad Rzeszutek Wilk "%04x:%02x:%02x.%02x", domain, bus, 21830edc14bSKonrad Rzeszutek Wilk PCI_SLOT(devfn), PCI_FUNC(devfn)); 21930edc14bSKonrad Rzeszutek Wilk 22030edc14bSKonrad Rzeszutek Wilk out: 22130edc14bSKonrad Rzeszutek Wilk return err; 22230edc14bSKonrad Rzeszutek Wilk } 22330edc14bSKonrad Rzeszutek Wilk 224a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_export_device(struct xen_pcibk_device *pdev, 22530edc14bSKonrad Rzeszutek Wilk int domain, int bus, int slot, int func, 22630edc14bSKonrad Rzeszutek Wilk int devid) 22730edc14bSKonrad Rzeszutek Wilk { 22830edc14bSKonrad Rzeszutek Wilk struct pci_dev *dev; 22930edc14bSKonrad Rzeszutek Wilk int err = 0; 23030edc14bSKonrad Rzeszutek Wilk 23130edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n", 23230edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 23330edc14bSKonrad Rzeszutek Wilk 23430edc14bSKonrad Rzeszutek Wilk dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func); 23530edc14bSKonrad Rzeszutek Wilk if (!dev) { 23630edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 23730edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 23830edc14bSKonrad Rzeszutek Wilk "Couldn't locate PCI device " 239e4de866aSKonrad Rzeszutek Wilk "(%04x:%02x:%02x.%d)! " 24030edc14bSKonrad Rzeszutek Wilk "perhaps already in-use?", 24130edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 24230edc14bSKonrad Rzeszutek Wilk goto out; 24330edc14bSKonrad Rzeszutek Wilk } 24430edc14bSKonrad Rzeszutek Wilk 245a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_add_pci_dev(pdev, dev, devid, 246a92336a1SKonrad Rzeszutek Wilk xen_pcibk_publish_pci_dev); 24730edc14bSKonrad Rzeszutek Wilk if (err) 24830edc14bSKonrad Rzeszutek Wilk goto out; 24930edc14bSKonrad Rzeszutek Wilk 25015390613SKonrad Rzeszutek Wilk dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id); 2516221a9b2SKonrad Rzeszutek Wilk if (xen_register_device_domain_owner(dev, 2526221a9b2SKonrad Rzeszutek Wilk pdev->xdev->otherend_id) != 0) { 2536c254de1SKonrad Rzeszutek Wilk dev_err(&dev->dev, "Stealing ownership from dom%d.\n", 2546c254de1SKonrad Rzeszutek Wilk xen_find_device_domain_owner(dev)); 2556221a9b2SKonrad Rzeszutek Wilk xen_unregister_device_domain_owner(dev); 2566221a9b2SKonrad Rzeszutek Wilk xen_register_device_domain_owner(dev, pdev->xdev->otherend_id); 2576221a9b2SKonrad Rzeszutek Wilk } 2586221a9b2SKonrad Rzeszutek Wilk 25930edc14bSKonrad Rzeszutek Wilk /* TODO: It'd be nice to export a bridge and have all of its children 26030edc14bSKonrad Rzeszutek Wilk * get exported with it. This may be best done in xend (which will 26130edc14bSKonrad Rzeszutek Wilk * have to calculate resource usage anyway) but we probably want to 26230edc14bSKonrad Rzeszutek Wilk * put something in here to ensure that if a bridge gets given to a 26330edc14bSKonrad Rzeszutek Wilk * driver domain, that all devices under that bridge are not given 26430edc14bSKonrad Rzeszutek Wilk * to other driver domains (as he who controls the bridge can disable 26530edc14bSKonrad Rzeszutek Wilk * it and stop the other devices from working). 26630edc14bSKonrad Rzeszutek Wilk */ 26730edc14bSKonrad Rzeszutek Wilk out: 26830edc14bSKonrad Rzeszutek Wilk return err; 26930edc14bSKonrad Rzeszutek Wilk } 27030edc14bSKonrad Rzeszutek Wilk 271a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_remove_device(struct xen_pcibk_device *pdev, 27230edc14bSKonrad Rzeszutek Wilk int domain, int bus, int slot, int func) 27330edc14bSKonrad Rzeszutek Wilk { 27430edc14bSKonrad Rzeszutek Wilk int err = 0; 27530edc14bSKonrad Rzeszutek Wilk struct pci_dev *dev; 27630edc14bSKonrad Rzeszutek Wilk 27730edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n", 27830edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 27930edc14bSKonrad Rzeszutek Wilk 280a92336a1SKonrad Rzeszutek Wilk dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func)); 28130edc14bSKonrad Rzeszutek Wilk if (!dev) { 28230edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 28330edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device " 284e4de866aSKonrad Rzeszutek Wilk "(%04x:%02x:%02x.%d)! not owned by this domain\n", 28530edc14bSKonrad Rzeszutek Wilk domain, bus, slot, func); 28630edc14bSKonrad Rzeszutek Wilk goto out; 28730edc14bSKonrad Rzeszutek Wilk } 28830edc14bSKonrad Rzeszutek Wilk 2896221a9b2SKonrad Rzeszutek Wilk dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id); 2906221a9b2SKonrad Rzeszutek Wilk xen_unregister_device_domain_owner(dev); 2916221a9b2SKonrad Rzeszutek Wilk 2928be9df6dSKonrad Rzeszutek Wilk /* N.B. This ends up calling pcistub_put_pci_dev which ends up 2938be9df6dSKonrad Rzeszutek Wilk * doing the FLR. */ 294e8801a74SKonrad Rzeszutek Wilk xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */); 29530edc14bSKonrad Rzeszutek Wilk 29630edc14bSKonrad Rzeszutek Wilk out: 29730edc14bSKonrad Rzeszutek Wilk return err; 29830edc14bSKonrad Rzeszutek Wilk } 29930edc14bSKonrad Rzeszutek Wilk 300a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev, 30130edc14bSKonrad Rzeszutek Wilk unsigned int domain, unsigned int bus) 30230edc14bSKonrad Rzeszutek Wilk { 30330edc14bSKonrad Rzeszutek Wilk unsigned int d, b; 30430edc14bSKonrad Rzeszutek Wilk int i, root_num, len, err; 30530edc14bSKonrad Rzeszutek Wilk char str[64]; 30630edc14bSKonrad Rzeszutek Wilk 30730edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n"); 30830edc14bSKonrad Rzeszutek Wilk 30930edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 31030edc14bSKonrad Rzeszutek Wilk "root_num", "%d", &root_num); 31130edc14bSKonrad Rzeszutek Wilk if (err == 0 || err == -ENOENT) 31230edc14bSKonrad Rzeszutek Wilk root_num = 0; 31330edc14bSKonrad Rzeszutek Wilk else if (err < 0) 31430edc14bSKonrad Rzeszutek Wilk goto out; 31530edc14bSKonrad Rzeszutek Wilk 31630edc14bSKonrad Rzeszutek Wilk /* Verify that we haven't already published this pci root */ 31730edc14bSKonrad Rzeszutek Wilk for (i = 0; i < root_num; i++) { 31830edc14bSKonrad Rzeszutek Wilk len = snprintf(str, sizeof(str), "root-%d", i); 31930edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(str) - 1))) { 32030edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 32130edc14bSKonrad Rzeszutek Wilk goto out; 32230edc14bSKonrad Rzeszutek Wilk } 32330edc14bSKonrad Rzeszutek Wilk 32430edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 32530edc14bSKonrad Rzeszutek Wilk str, "%x:%x", &d, &b); 32630edc14bSKonrad Rzeszutek Wilk if (err < 0) 32730edc14bSKonrad Rzeszutek Wilk goto out; 32830edc14bSKonrad Rzeszutek Wilk if (err != 2) { 32930edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 33030edc14bSKonrad Rzeszutek Wilk goto out; 33130edc14bSKonrad Rzeszutek Wilk } 33230edc14bSKonrad Rzeszutek Wilk 33330edc14bSKonrad Rzeszutek Wilk if (d == domain && b == bus) { 33430edc14bSKonrad Rzeszutek Wilk err = 0; 33530edc14bSKonrad Rzeszutek Wilk goto out; 33630edc14bSKonrad Rzeszutek Wilk } 33730edc14bSKonrad Rzeszutek Wilk } 33830edc14bSKonrad Rzeszutek Wilk 33930edc14bSKonrad Rzeszutek Wilk len = snprintf(str, sizeof(str), "root-%d", root_num); 34030edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(str) - 1))) { 34130edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 34230edc14bSKonrad Rzeszutek Wilk goto out; 34330edc14bSKonrad Rzeszutek Wilk } 34430edc14bSKonrad Rzeszutek Wilk 34530edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n", 34630edc14bSKonrad Rzeszutek Wilk root_num, domain, bus); 34730edc14bSKonrad Rzeszutek Wilk 34830edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, 34930edc14bSKonrad Rzeszutek Wilk "%04x:%02x", domain, bus); 35030edc14bSKonrad Rzeszutek Wilk if (err) 35130edc14bSKonrad Rzeszutek Wilk goto out; 35230edc14bSKonrad Rzeszutek Wilk 35330edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, 35430edc14bSKonrad Rzeszutek Wilk "root_num", "%d", (root_num + 1)); 35530edc14bSKonrad Rzeszutek Wilk 35630edc14bSKonrad Rzeszutek Wilk out: 35730edc14bSKonrad Rzeszutek Wilk return err; 35830edc14bSKonrad Rzeszutek Wilk } 35930edc14bSKonrad Rzeszutek Wilk 360a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev) 36130edc14bSKonrad Rzeszutek Wilk { 36230edc14bSKonrad Rzeszutek Wilk int err = 0; 36330edc14bSKonrad Rzeszutek Wilk int num_devs; 36430edc14bSKonrad Rzeszutek Wilk int domain, bus, slot, func; 36530edc14bSKonrad Rzeszutek Wilk int substate; 36630edc14bSKonrad Rzeszutek Wilk int i, len; 36730edc14bSKonrad Rzeszutek Wilk char state_str[64]; 36830edc14bSKonrad Rzeszutek Wilk char dev_str[64]; 36930edc14bSKonrad Rzeszutek Wilk 37030edc14bSKonrad Rzeszutek Wilk 37130edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n"); 37230edc14bSKonrad Rzeszutek Wilk 373b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 37430edc14bSKonrad Rzeszutek Wilk /* Make sure we only reconfigure once */ 37530edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->nodename) != 37630edc14bSKonrad Rzeszutek Wilk XenbusStateReconfiguring) 37730edc14bSKonrad Rzeszutek Wilk goto out; 37830edc14bSKonrad Rzeszutek Wilk 37930edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", 38030edc14bSKonrad Rzeszutek Wilk &num_devs); 38130edc14bSKonrad Rzeszutek Wilk if (err != 1) { 38230edc14bSKonrad Rzeszutek Wilk if (err >= 0) 38330edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 38430edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 38530edc14bSKonrad Rzeszutek Wilk "Error reading number of devices"); 38630edc14bSKonrad Rzeszutek Wilk goto out; 38730edc14bSKonrad Rzeszutek Wilk } 38830edc14bSKonrad Rzeszutek Wilk 38930edc14bSKonrad Rzeszutek Wilk for (i = 0; i < num_devs; i++) { 39030edc14bSKonrad Rzeszutek Wilk len = snprintf(state_str, sizeof(state_str), "state-%d", i); 39130edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(state_str) - 1))) { 39230edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 39330edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 39430edc14bSKonrad Rzeszutek Wilk "String overflow while reading " 39530edc14bSKonrad Rzeszutek Wilk "configuration"); 39630edc14bSKonrad Rzeszutek Wilk goto out; 39730edc14bSKonrad Rzeszutek Wilk } 39830edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, state_str, 39930edc14bSKonrad Rzeszutek Wilk "%d", &substate); 40030edc14bSKonrad Rzeszutek Wilk if (err != 1) 40130edc14bSKonrad Rzeszutek Wilk substate = XenbusStateUnknown; 40230edc14bSKonrad Rzeszutek Wilk 40330edc14bSKonrad Rzeszutek Wilk switch (substate) { 40430edc14bSKonrad Rzeszutek Wilk case XenbusStateInitialising: 40530edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i); 40630edc14bSKonrad Rzeszutek Wilk 40730edc14bSKonrad Rzeszutek Wilk len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); 40830edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(dev_str) - 1))) { 40930edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 41030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 41130edc14bSKonrad Rzeszutek Wilk "String overflow while " 41230edc14bSKonrad Rzeszutek Wilk "reading configuration"); 41330edc14bSKonrad Rzeszutek Wilk goto out; 41430edc14bSKonrad Rzeszutek Wilk } 41530edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 41630edc14bSKonrad Rzeszutek Wilk dev_str, "%x:%x:%x.%x", 41730edc14bSKonrad Rzeszutek Wilk &domain, &bus, &slot, &func); 41830edc14bSKonrad Rzeszutek Wilk if (err < 0) { 41930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 42030edc14bSKonrad Rzeszutek Wilk "Error reading device " 42130edc14bSKonrad Rzeszutek Wilk "configuration"); 42230edc14bSKonrad Rzeszutek Wilk goto out; 42330edc14bSKonrad Rzeszutek Wilk } 42430edc14bSKonrad Rzeszutek Wilk if (err != 4) { 42530edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 42630edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 42730edc14bSKonrad Rzeszutek Wilk "Error parsing pci device " 42830edc14bSKonrad Rzeszutek Wilk "configuration"); 42930edc14bSKonrad Rzeszutek Wilk goto out; 43030edc14bSKonrad Rzeszutek Wilk } 43130edc14bSKonrad Rzeszutek Wilk 432a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_export_device(pdev, domain, bus, slot, 43330edc14bSKonrad Rzeszutek Wilk func, i); 43430edc14bSKonrad Rzeszutek Wilk if (err) 43530edc14bSKonrad Rzeszutek Wilk goto out; 43630edc14bSKonrad Rzeszutek Wilk 43730edc14bSKonrad Rzeszutek Wilk /* Publish pci roots. */ 438a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_publish_pci_roots(pdev, 439a92336a1SKonrad Rzeszutek Wilk xen_pcibk_publish_pci_root); 44030edc14bSKonrad Rzeszutek Wilk if (err) { 44130edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 44230edc14bSKonrad Rzeszutek Wilk "Error while publish PCI root" 44330edc14bSKonrad Rzeszutek Wilk "buses for frontend"); 44430edc14bSKonrad Rzeszutek Wilk goto out; 44530edc14bSKonrad Rzeszutek Wilk } 44630edc14bSKonrad Rzeszutek Wilk 44730edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, 44830edc14bSKonrad Rzeszutek Wilk state_str, "%d", 44930edc14bSKonrad Rzeszutek Wilk XenbusStateInitialised); 45030edc14bSKonrad Rzeszutek Wilk if (err) { 45130edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 45230edc14bSKonrad Rzeszutek Wilk "Error switching substate of " 45330edc14bSKonrad Rzeszutek Wilk "dev-%d\n", i); 45430edc14bSKonrad Rzeszutek Wilk goto out; 45530edc14bSKonrad Rzeszutek Wilk } 45630edc14bSKonrad Rzeszutek Wilk break; 45730edc14bSKonrad Rzeszutek Wilk 45830edc14bSKonrad Rzeszutek Wilk case XenbusStateClosing: 45930edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i); 46030edc14bSKonrad Rzeszutek Wilk 46130edc14bSKonrad Rzeszutek Wilk len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i); 46230edc14bSKonrad Rzeszutek Wilk if (unlikely(len >= (sizeof(dev_str) - 1))) { 46330edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 46430edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 46530edc14bSKonrad Rzeszutek Wilk "String overflow while " 46630edc14bSKonrad Rzeszutek Wilk "reading configuration"); 46730edc14bSKonrad Rzeszutek Wilk goto out; 46830edc14bSKonrad Rzeszutek Wilk } 46930edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 47030edc14bSKonrad Rzeszutek Wilk dev_str, "%x:%x:%x.%x", 47130edc14bSKonrad Rzeszutek Wilk &domain, &bus, &slot, &func); 47230edc14bSKonrad Rzeszutek Wilk if (err < 0) { 47330edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 47430edc14bSKonrad Rzeszutek Wilk "Error reading device " 47530edc14bSKonrad Rzeszutek Wilk "configuration"); 47630edc14bSKonrad Rzeszutek Wilk goto out; 47730edc14bSKonrad Rzeszutek Wilk } 47830edc14bSKonrad Rzeszutek Wilk if (err != 4) { 47930edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 48030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 48130edc14bSKonrad Rzeszutek Wilk "Error parsing pci device " 48230edc14bSKonrad Rzeszutek Wilk "configuration"); 48330edc14bSKonrad Rzeszutek Wilk goto out; 48430edc14bSKonrad Rzeszutek Wilk } 48530edc14bSKonrad Rzeszutek Wilk 486a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_remove_device(pdev, domain, bus, slot, 48730edc14bSKonrad Rzeszutek Wilk func); 48830edc14bSKonrad Rzeszutek Wilk if (err) 48930edc14bSKonrad Rzeszutek Wilk goto out; 49030edc14bSKonrad Rzeszutek Wilk 49130edc14bSKonrad Rzeszutek Wilk /* TODO: If at some point we implement support for pci 49230edc14bSKonrad Rzeszutek Wilk * root hot-remove on pcifront side, we'll need to 49330edc14bSKonrad Rzeszutek Wilk * remove unnecessary xenstore nodes of pci roots here. 49430edc14bSKonrad Rzeszutek Wilk */ 49530edc14bSKonrad Rzeszutek Wilk 49630edc14bSKonrad Rzeszutek Wilk break; 49730edc14bSKonrad Rzeszutek Wilk 49830edc14bSKonrad Rzeszutek Wilk default: 49930edc14bSKonrad Rzeszutek Wilk break; 50030edc14bSKonrad Rzeszutek Wilk } 50130edc14bSKonrad Rzeszutek Wilk } 50230edc14bSKonrad Rzeszutek Wilk 50330edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured); 50430edc14bSKonrad Rzeszutek Wilk if (err) { 50530edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 50630edc14bSKonrad Rzeszutek Wilk "Error switching to reconfigured state!"); 50730edc14bSKonrad Rzeszutek Wilk goto out; 50830edc14bSKonrad Rzeszutek Wilk } 50930edc14bSKonrad Rzeszutek Wilk 51030edc14bSKonrad Rzeszutek Wilk out: 511b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 51230edc14bSKonrad Rzeszutek Wilk return 0; 51330edc14bSKonrad Rzeszutek Wilk } 51430edc14bSKonrad Rzeszutek Wilk 515a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_frontend_changed(struct xenbus_device *xdev, 51630edc14bSKonrad Rzeszutek Wilk enum xenbus_state fe_state) 51730edc14bSKonrad Rzeszutek Wilk { 518a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev); 51930edc14bSKonrad Rzeszutek Wilk 52030edc14bSKonrad Rzeszutek Wilk dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state); 52130edc14bSKonrad Rzeszutek Wilk 52230edc14bSKonrad Rzeszutek Wilk switch (fe_state) { 52330edc14bSKonrad Rzeszutek Wilk case XenbusStateInitialised: 524a92336a1SKonrad Rzeszutek Wilk xen_pcibk_attach(pdev); 52530edc14bSKonrad Rzeszutek Wilk break; 52630edc14bSKonrad Rzeszutek Wilk 52730edc14bSKonrad Rzeszutek Wilk case XenbusStateReconfiguring: 528a92336a1SKonrad Rzeszutek Wilk xen_pcibk_reconfigure(pdev); 52930edc14bSKonrad Rzeszutek Wilk break; 53030edc14bSKonrad Rzeszutek Wilk 53130edc14bSKonrad Rzeszutek Wilk case XenbusStateConnected: 53230edc14bSKonrad Rzeszutek Wilk /* pcifront switched its state from reconfiguring to connected. 53330edc14bSKonrad Rzeszutek Wilk * Then switch to connected state. 53430edc14bSKonrad Rzeszutek Wilk */ 53530edc14bSKonrad Rzeszutek Wilk xenbus_switch_state(xdev, XenbusStateConnected); 53630edc14bSKonrad Rzeszutek Wilk break; 53730edc14bSKonrad Rzeszutek Wilk 53830edc14bSKonrad Rzeszutek Wilk case XenbusStateClosing: 539a92336a1SKonrad Rzeszutek Wilk xen_pcibk_disconnect(pdev); 54030edc14bSKonrad Rzeszutek Wilk xenbus_switch_state(xdev, XenbusStateClosing); 54130edc14bSKonrad Rzeszutek Wilk break; 54230edc14bSKonrad Rzeszutek Wilk 54330edc14bSKonrad Rzeszutek Wilk case XenbusStateClosed: 544a92336a1SKonrad Rzeszutek Wilk xen_pcibk_disconnect(pdev); 54530edc14bSKonrad Rzeszutek Wilk xenbus_switch_state(xdev, XenbusStateClosed); 54630edc14bSKonrad Rzeszutek Wilk if (xenbus_dev_is_online(xdev)) 54730edc14bSKonrad Rzeszutek Wilk break; 54830edc14bSKonrad Rzeszutek Wilk /* fall through if not online */ 54930edc14bSKonrad Rzeszutek Wilk case XenbusStateUnknown: 55030edc14bSKonrad Rzeszutek Wilk dev_dbg(&xdev->dev, "frontend is gone! unregister device\n"); 55130edc14bSKonrad Rzeszutek Wilk device_unregister(&xdev->dev); 55230edc14bSKonrad Rzeszutek Wilk break; 55330edc14bSKonrad Rzeszutek Wilk 55430edc14bSKonrad Rzeszutek Wilk default: 55530edc14bSKonrad Rzeszutek Wilk break; 55630edc14bSKonrad Rzeszutek Wilk } 55730edc14bSKonrad Rzeszutek Wilk } 55830edc14bSKonrad Rzeszutek Wilk 559a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev) 56030edc14bSKonrad Rzeszutek Wilk { 56130edc14bSKonrad Rzeszutek Wilk /* Get configuration from xend (if available now) */ 56230edc14bSKonrad Rzeszutek Wilk int domain, bus, slot, func; 56330edc14bSKonrad Rzeszutek Wilk int err = 0; 56430edc14bSKonrad Rzeszutek Wilk int i, num_devs; 56530edc14bSKonrad Rzeszutek Wilk char dev_str[64]; 56630edc14bSKonrad Rzeszutek Wilk char state_str[64]; 56730edc14bSKonrad Rzeszutek Wilk 568b1766b62SKonrad Rzeszutek Wilk mutex_lock(&pdev->dev_lock); 56930edc14bSKonrad Rzeszutek Wilk /* It's possible we could get the call to setup twice, so make sure 57030edc14bSKonrad Rzeszutek Wilk * we're not already connected. 57130edc14bSKonrad Rzeszutek Wilk */ 57230edc14bSKonrad Rzeszutek Wilk if (xenbus_read_driver_state(pdev->xdev->nodename) != 57330edc14bSKonrad Rzeszutek Wilk XenbusStateInitWait) 57430edc14bSKonrad Rzeszutek Wilk goto out; 57530edc14bSKonrad Rzeszutek Wilk 57630edc14bSKonrad Rzeszutek Wilk dev_dbg(&pdev->xdev->dev, "getting be setup\n"); 57730edc14bSKonrad Rzeszutek Wilk 57830edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", 57930edc14bSKonrad Rzeszutek Wilk &num_devs); 58030edc14bSKonrad Rzeszutek Wilk if (err != 1) { 58130edc14bSKonrad Rzeszutek Wilk if (err >= 0) 58230edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 58330edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 58430edc14bSKonrad Rzeszutek Wilk "Error reading number of devices"); 58530edc14bSKonrad Rzeszutek Wilk goto out; 58630edc14bSKonrad Rzeszutek Wilk } 58730edc14bSKonrad Rzeszutek Wilk 58830edc14bSKonrad Rzeszutek Wilk for (i = 0; i < num_devs; i++) { 58930edc14bSKonrad Rzeszutek Wilk int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); 59030edc14bSKonrad Rzeszutek Wilk if (unlikely(l >= (sizeof(dev_str) - 1))) { 59130edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 59230edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 59330edc14bSKonrad Rzeszutek Wilk "String overflow while reading " 59430edc14bSKonrad Rzeszutek Wilk "configuration"); 59530edc14bSKonrad Rzeszutek Wilk goto out; 59630edc14bSKonrad Rzeszutek Wilk } 59730edc14bSKonrad Rzeszutek Wilk 59830edc14bSKonrad Rzeszutek Wilk err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str, 59930edc14bSKonrad Rzeszutek Wilk "%x:%x:%x.%x", &domain, &bus, &slot, &func); 60030edc14bSKonrad Rzeszutek Wilk if (err < 0) { 60130edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 60230edc14bSKonrad Rzeszutek Wilk "Error reading device configuration"); 60330edc14bSKonrad Rzeszutek Wilk goto out; 60430edc14bSKonrad Rzeszutek Wilk } 60530edc14bSKonrad Rzeszutek Wilk if (err != 4) { 60630edc14bSKonrad Rzeszutek Wilk err = -EINVAL; 60730edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 60830edc14bSKonrad Rzeszutek Wilk "Error parsing pci device " 60930edc14bSKonrad Rzeszutek Wilk "configuration"); 61030edc14bSKonrad Rzeszutek Wilk goto out; 61130edc14bSKonrad Rzeszutek Wilk } 61230edc14bSKonrad Rzeszutek Wilk 613a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i); 61430edc14bSKonrad Rzeszutek Wilk if (err) 61530edc14bSKonrad Rzeszutek Wilk goto out; 61630edc14bSKonrad Rzeszutek Wilk 61730edc14bSKonrad Rzeszutek Wilk /* Switch substate of this device. */ 61830edc14bSKonrad Rzeszutek Wilk l = snprintf(state_str, sizeof(state_str), "state-%d", i); 61930edc14bSKonrad Rzeszutek Wilk if (unlikely(l >= (sizeof(state_str) - 1))) { 62030edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 62130edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 62230edc14bSKonrad Rzeszutek Wilk "String overflow while reading " 62330edc14bSKonrad Rzeszutek Wilk "configuration"); 62430edc14bSKonrad Rzeszutek Wilk goto out; 62530edc14bSKonrad Rzeszutek Wilk } 62630edc14bSKonrad Rzeszutek Wilk err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str, 62730edc14bSKonrad Rzeszutek Wilk "%d", XenbusStateInitialised); 62830edc14bSKonrad Rzeszutek Wilk if (err) { 62930edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, "Error switching " 63030edc14bSKonrad Rzeszutek Wilk "substate of dev-%d\n", i); 63130edc14bSKonrad Rzeszutek Wilk goto out; 63230edc14bSKonrad Rzeszutek Wilk } 63330edc14bSKonrad Rzeszutek Wilk } 63430edc14bSKonrad Rzeszutek Wilk 635a92336a1SKonrad Rzeszutek Wilk err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root); 63630edc14bSKonrad Rzeszutek Wilk if (err) { 63730edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 63830edc14bSKonrad Rzeszutek Wilk "Error while publish PCI root buses " 63930edc14bSKonrad Rzeszutek Wilk "for frontend"); 64030edc14bSKonrad Rzeszutek Wilk goto out; 64130edc14bSKonrad Rzeszutek Wilk } 64230edc14bSKonrad Rzeszutek Wilk 64330edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised); 64430edc14bSKonrad Rzeszutek Wilk if (err) 64530edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(pdev->xdev, err, 64630edc14bSKonrad Rzeszutek Wilk "Error switching to initialised state!"); 64730edc14bSKonrad Rzeszutek Wilk 64830edc14bSKonrad Rzeszutek Wilk out: 649b1766b62SKonrad Rzeszutek Wilk mutex_unlock(&pdev->dev_lock); 65030edc14bSKonrad Rzeszutek Wilk if (!err) 65130edc14bSKonrad Rzeszutek Wilk /* see if pcifront is already configured (if not, we'll wait) */ 652a92336a1SKonrad Rzeszutek Wilk xen_pcibk_attach(pdev); 65330edc14bSKonrad Rzeszutek Wilk return err; 65430edc14bSKonrad Rzeszutek Wilk } 65530edc14bSKonrad Rzeszutek Wilk 656a92336a1SKonrad Rzeszutek Wilk static void xen_pcibk_be_watch(struct xenbus_watch *watch, 65730edc14bSKonrad Rzeszutek Wilk const char **vec, unsigned int len) 65830edc14bSKonrad Rzeszutek Wilk { 659a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = 660a92336a1SKonrad Rzeszutek Wilk container_of(watch, struct xen_pcibk_device, be_watch); 66130edc14bSKonrad Rzeszutek Wilk 66230edc14bSKonrad Rzeszutek Wilk switch (xenbus_read_driver_state(pdev->xdev->nodename)) { 66330edc14bSKonrad Rzeszutek Wilk case XenbusStateInitWait: 664a92336a1SKonrad Rzeszutek Wilk xen_pcibk_setup_backend(pdev); 66530edc14bSKonrad Rzeszutek Wilk break; 66630edc14bSKonrad Rzeszutek Wilk 66730edc14bSKonrad Rzeszutek Wilk default: 66830edc14bSKonrad Rzeszutek Wilk break; 66930edc14bSKonrad Rzeszutek Wilk } 67030edc14bSKonrad Rzeszutek Wilk } 67130edc14bSKonrad Rzeszutek Wilk 672a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_xenbus_probe(struct xenbus_device *dev, 67330edc14bSKonrad Rzeszutek Wilk const struct xenbus_device_id *id) 67430edc14bSKonrad Rzeszutek Wilk { 67530edc14bSKonrad Rzeszutek Wilk int err = 0; 676a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = alloc_pdev(dev); 67730edc14bSKonrad Rzeszutek Wilk 67830edc14bSKonrad Rzeszutek Wilk if (pdev == NULL) { 67930edc14bSKonrad Rzeszutek Wilk err = -ENOMEM; 68030edc14bSKonrad Rzeszutek Wilk xenbus_dev_fatal(dev, err, 681a92336a1SKonrad Rzeszutek Wilk "Error allocating xen_pcibk_device struct"); 68230edc14bSKonrad Rzeszutek Wilk goto out; 68330edc14bSKonrad Rzeszutek Wilk } 68430edc14bSKonrad Rzeszutek Wilk 68530edc14bSKonrad Rzeszutek Wilk /* wait for xend to configure us */ 68630edc14bSKonrad Rzeszutek Wilk err = xenbus_switch_state(dev, XenbusStateInitWait); 68730edc14bSKonrad Rzeszutek Wilk if (err) 68830edc14bSKonrad Rzeszutek Wilk goto out; 68930edc14bSKonrad Rzeszutek Wilk 69030edc14bSKonrad Rzeszutek Wilk /* watch the backend node for backend configuration information */ 69130edc14bSKonrad Rzeszutek Wilk err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch, 692a92336a1SKonrad Rzeszutek Wilk xen_pcibk_be_watch); 69330edc14bSKonrad Rzeszutek Wilk if (err) 69430edc14bSKonrad Rzeszutek Wilk goto out; 695494ef20dSKonrad Rzeszutek Wilk 69630edc14bSKonrad Rzeszutek Wilk pdev->be_watching = 1; 69730edc14bSKonrad Rzeszutek Wilk 69830edc14bSKonrad Rzeszutek Wilk /* We need to force a call to our callback here in case 69930edc14bSKonrad Rzeszutek Wilk * xend already configured us! 70030edc14bSKonrad Rzeszutek Wilk */ 701a92336a1SKonrad Rzeszutek Wilk xen_pcibk_be_watch(&pdev->be_watch, NULL, 0); 70230edc14bSKonrad Rzeszutek Wilk 70330edc14bSKonrad Rzeszutek Wilk out: 70430edc14bSKonrad Rzeszutek Wilk return err; 70530edc14bSKonrad Rzeszutek Wilk } 70630edc14bSKonrad Rzeszutek Wilk 707a92336a1SKonrad Rzeszutek Wilk static int xen_pcibk_xenbus_remove(struct xenbus_device *dev) 70830edc14bSKonrad Rzeszutek Wilk { 709a92336a1SKonrad Rzeszutek Wilk struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev); 71030edc14bSKonrad Rzeszutek Wilk 71130edc14bSKonrad Rzeszutek Wilk if (pdev != NULL) 71230edc14bSKonrad Rzeszutek Wilk free_pdev(pdev); 71330edc14bSKonrad Rzeszutek Wilk 71430edc14bSKonrad Rzeszutek Wilk return 0; 71530edc14bSKonrad Rzeszutek Wilk } 71630edc14bSKonrad Rzeszutek Wilk 71773db144bSJan Beulich static const struct xenbus_device_id xen_pcibk_ids[] = { 71830edc14bSKonrad Rzeszutek Wilk {"pci"}, 71930edc14bSKonrad Rzeszutek Wilk {""}, 72030edc14bSKonrad Rzeszutek Wilk }; 72130edc14bSKonrad Rzeszutek Wilk 72295afae48SDavid Vrabel static struct xenbus_driver xen_pcibk_driver = { 72395afae48SDavid Vrabel .name = DRV_NAME, 72495afae48SDavid Vrabel .ids = xen_pcibk_ids, 725a92336a1SKonrad Rzeszutek Wilk .probe = xen_pcibk_xenbus_probe, 726a92336a1SKonrad Rzeszutek Wilk .remove = xen_pcibk_xenbus_remove, 727a92336a1SKonrad Rzeszutek Wilk .otherend_changed = xen_pcibk_frontend_changed, 72895afae48SDavid Vrabel }; 72930edc14bSKonrad Rzeszutek Wilk 730402c5e15SJan Beulich const struct xen_pcibk_backend *__read_mostly xen_pcibk_backend; 7312ebdc426SKonrad Rzeszutek Wilk 732a92336a1SKonrad Rzeszutek Wilk int __init xen_pcibk_xenbus_register(void) 73330edc14bSKonrad Rzeszutek Wilk { 734a92336a1SKonrad Rzeszutek Wilk xen_pcibk_wq = create_workqueue("xen_pciback_workqueue"); 735a92336a1SKonrad Rzeszutek Wilk if (!xen_pcibk_wq) { 736283c0972SJoe Perches pr_err("%s: create xen_pciback_workqueue failed\n", __func__); 73730edc14bSKonrad Rzeszutek Wilk return -EFAULT; 73830edc14bSKonrad Rzeszutek Wilk } 7392ebdc426SKonrad Rzeszutek Wilk xen_pcibk_backend = &xen_pcibk_vpci_backend; 7402ebdc426SKonrad Rzeszutek Wilk if (passthrough) 7412ebdc426SKonrad Rzeszutek Wilk xen_pcibk_backend = &xen_pcibk_passthrough_backend; 742283c0972SJoe Perches pr_info("backend is %s\n", xen_pcibk_backend->name); 74373db144bSJan Beulich return xenbus_register_backend(&xen_pcibk_driver); 74430edc14bSKonrad Rzeszutek Wilk } 74530edc14bSKonrad Rzeszutek Wilk 746a92336a1SKonrad Rzeszutek Wilk void __exit xen_pcibk_xenbus_unregister(void) 74730edc14bSKonrad Rzeszutek Wilk { 748a92336a1SKonrad Rzeszutek Wilk destroy_workqueue(xen_pcibk_wq); 74973db144bSJan Beulich xenbus_unregister_driver(&xen_pcibk_driver); 75030edc14bSKonrad Rzeszutek Wilk } 751