18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * PCI Backend Xenbus Setup - handles setup with frontend and xend 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/moduleparam.h> 118c2ecf20Sopenharmony_ci#include <linux/init.h> 128c2ecf20Sopenharmony_ci#include <linux/list.h> 138c2ecf20Sopenharmony_ci#include <linux/vmalloc.h> 148c2ecf20Sopenharmony_ci#include <linux/workqueue.h> 158c2ecf20Sopenharmony_ci#include <xen/xenbus.h> 168c2ecf20Sopenharmony_ci#include <xen/events.h> 178c2ecf20Sopenharmony_ci#include <asm/xen/pci.h> 188c2ecf20Sopenharmony_ci#include "pciback.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#define INVALID_EVTCHN_IRQ (-1) 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic bool __read_mostly passthrough; 238c2ecf20Sopenharmony_cimodule_param(passthrough, bool, S_IRUGO); 248c2ecf20Sopenharmony_ciMODULE_PARM_DESC(passthrough, 258c2ecf20Sopenharmony_ci "Option to specify how to export PCI topology to guest:\n"\ 268c2ecf20Sopenharmony_ci " 0 - (default) Hide the true PCI topology and makes the frontend\n"\ 278c2ecf20Sopenharmony_ci " there is a single PCI bus with only the exported devices on it.\n"\ 288c2ecf20Sopenharmony_ci " For example, a device at 03:05.0 will be re-assigned to 00:00.0\n"\ 298c2ecf20Sopenharmony_ci " while second device at 02:1a.1 will be re-assigned to 00:01.1.\n"\ 308c2ecf20Sopenharmony_ci " 1 - Passthrough provides a real view of the PCI topology to the\n"\ 318c2ecf20Sopenharmony_ci " frontend (for example, a device at 06:01.b will still appear at\n"\ 328c2ecf20Sopenharmony_ci " 06:01.b to the frontend). This is similar to how Xen 2.0.x\n"\ 338c2ecf20Sopenharmony_ci " exposed PCI devices to its driver domains. This may be required\n"\ 348c2ecf20Sopenharmony_ci " for drivers which depend on finding their hardward in certain\n"\ 358c2ecf20Sopenharmony_ci " bus/slot locations."); 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_cistatic struct xen_pcibk_device *alloc_pdev(struct xenbus_device *xdev) 388c2ecf20Sopenharmony_ci{ 398c2ecf20Sopenharmony_ci struct xen_pcibk_device *pdev; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci pdev = kzalloc(sizeof(struct xen_pcibk_device), GFP_KERNEL); 428c2ecf20Sopenharmony_ci if (pdev == NULL) 438c2ecf20Sopenharmony_ci goto out; 448c2ecf20Sopenharmony_ci dev_dbg(&xdev->dev, "allocated pdev @ 0x%p\n", pdev); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci pdev->xdev = xdev; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_ci mutex_init(&pdev->dev_lock); 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci pdev->sh_info = NULL; 518c2ecf20Sopenharmony_ci pdev->evtchn_irq = INVALID_EVTCHN_IRQ; 528c2ecf20Sopenharmony_ci pdev->be_watching = 0; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci INIT_WORK(&pdev->op_work, xen_pcibk_do_op); 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (xen_pcibk_init_devices(pdev)) { 578c2ecf20Sopenharmony_ci kfree(pdev); 588c2ecf20Sopenharmony_ci pdev = NULL; 598c2ecf20Sopenharmony_ci } 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci dev_set_drvdata(&xdev->dev, pdev); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ciout: 648c2ecf20Sopenharmony_ci return pdev; 658c2ecf20Sopenharmony_ci} 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic void xen_pcibk_disconnect(struct xen_pcibk_device *pdev) 688c2ecf20Sopenharmony_ci{ 698c2ecf20Sopenharmony_ci mutex_lock(&pdev->dev_lock); 708c2ecf20Sopenharmony_ci /* Ensure the guest can't trigger our handler before removing devices */ 718c2ecf20Sopenharmony_ci if (pdev->evtchn_irq != INVALID_EVTCHN_IRQ) { 728c2ecf20Sopenharmony_ci unbind_from_irqhandler(pdev->evtchn_irq, pdev); 738c2ecf20Sopenharmony_ci pdev->evtchn_irq = INVALID_EVTCHN_IRQ; 748c2ecf20Sopenharmony_ci } 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci /* If the driver domain started an op, make sure we complete it 778c2ecf20Sopenharmony_ci * before releasing the shared memory */ 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci flush_work(&pdev->op_work); 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci if (pdev->sh_info != NULL) { 828c2ecf20Sopenharmony_ci xenbus_unmap_ring_vfree(pdev->xdev, pdev->sh_info); 838c2ecf20Sopenharmony_ci pdev->sh_info = NULL; 848c2ecf20Sopenharmony_ci } 858c2ecf20Sopenharmony_ci mutex_unlock(&pdev->dev_lock); 868c2ecf20Sopenharmony_ci} 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_cistatic void free_pdev(struct xen_pcibk_device *pdev) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci if (pdev->be_watching) { 918c2ecf20Sopenharmony_ci unregister_xenbus_watch(&pdev->be_watch); 928c2ecf20Sopenharmony_ci pdev->be_watching = 0; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci xen_pcibk_disconnect(pdev); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci /* N.B. This calls pcistub_put_pci_dev which does the FLR on all 988c2ecf20Sopenharmony_ci * of the PCIe devices. */ 998c2ecf20Sopenharmony_ci xen_pcibk_release_devices(pdev); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci dev_set_drvdata(&pdev->xdev->dev, NULL); 1028c2ecf20Sopenharmony_ci pdev->xdev = NULL; 1038c2ecf20Sopenharmony_ci 1048c2ecf20Sopenharmony_ci kfree(pdev); 1058c2ecf20Sopenharmony_ci} 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_cistatic int xen_pcibk_do_attach(struct xen_pcibk_device *pdev, int gnt_ref, 1088c2ecf20Sopenharmony_ci evtchn_port_t remote_evtchn) 1098c2ecf20Sopenharmony_ci{ 1108c2ecf20Sopenharmony_ci int err = 0; 1118c2ecf20Sopenharmony_ci void *vaddr; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, 1148c2ecf20Sopenharmony_ci "Attaching to frontend resources - gnt_ref=%d evtchn=%u\n", 1158c2ecf20Sopenharmony_ci gnt_ref, remote_evtchn); 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci err = xenbus_map_ring_valloc(pdev->xdev, &gnt_ref, 1, &vaddr); 1188c2ecf20Sopenharmony_ci if (err < 0) { 1198c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 1208c2ecf20Sopenharmony_ci "Error mapping other domain page in ours."); 1218c2ecf20Sopenharmony_ci goto out; 1228c2ecf20Sopenharmony_ci } 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci pdev->sh_info = vaddr; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci err = bind_interdomain_evtchn_to_irqhandler_lateeoi( 1278c2ecf20Sopenharmony_ci pdev->xdev->otherend_id, remote_evtchn, xen_pcibk_handle_event, 1288c2ecf20Sopenharmony_ci 0, DRV_NAME, pdev); 1298c2ecf20Sopenharmony_ci if (err < 0) { 1308c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 1318c2ecf20Sopenharmony_ci "Error binding event channel to IRQ"); 1328c2ecf20Sopenharmony_ci goto out; 1338c2ecf20Sopenharmony_ci } 1348c2ecf20Sopenharmony_ci pdev->evtchn_irq = err; 1358c2ecf20Sopenharmony_ci err = 0; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "Attached!\n"); 1388c2ecf20Sopenharmony_ciout: 1398c2ecf20Sopenharmony_ci return err; 1408c2ecf20Sopenharmony_ci} 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_cistatic int xen_pcibk_attach(struct xen_pcibk_device *pdev) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci int err = 0; 1458c2ecf20Sopenharmony_ci int gnt_ref; 1468c2ecf20Sopenharmony_ci evtchn_port_t remote_evtchn; 1478c2ecf20Sopenharmony_ci char *magic = NULL; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci mutex_lock(&pdev->dev_lock); 1518c2ecf20Sopenharmony_ci /* Make sure we only do this setup once */ 1528c2ecf20Sopenharmony_ci if (xenbus_read_driver_state(pdev->xdev->nodename) != 1538c2ecf20Sopenharmony_ci XenbusStateInitialised) 1548c2ecf20Sopenharmony_ci goto out; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci /* Wait for frontend to state that it has published the configuration */ 1578c2ecf20Sopenharmony_ci if (xenbus_read_driver_state(pdev->xdev->otherend) != 1588c2ecf20Sopenharmony_ci XenbusStateInitialised) 1598c2ecf20Sopenharmony_ci goto out; 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "Reading frontend config\n"); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci err = xenbus_gather(XBT_NIL, pdev->xdev->otherend, 1648c2ecf20Sopenharmony_ci "pci-op-ref", "%u", &gnt_ref, 1658c2ecf20Sopenharmony_ci "event-channel", "%u", &remote_evtchn, 1668c2ecf20Sopenharmony_ci "magic", NULL, &magic, NULL); 1678c2ecf20Sopenharmony_ci if (err) { 1688c2ecf20Sopenharmony_ci /* If configuration didn't get read correctly, wait longer */ 1698c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 1708c2ecf20Sopenharmony_ci "Error reading configuration from frontend"); 1718c2ecf20Sopenharmony_ci goto out; 1728c2ecf20Sopenharmony_ci } 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci if (magic == NULL || strcmp(magic, XEN_PCI_MAGIC) != 0) { 1758c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, -EFAULT, 1768c2ecf20Sopenharmony_ci "version mismatch (%s/%s) with pcifront - " 1778c2ecf20Sopenharmony_ci "halting " DRV_NAME, 1788c2ecf20Sopenharmony_ci magic, XEN_PCI_MAGIC); 1798c2ecf20Sopenharmony_ci err = -EFAULT; 1808c2ecf20Sopenharmony_ci goto out; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci err = xen_pcibk_do_attach(pdev, gnt_ref, remote_evtchn); 1848c2ecf20Sopenharmony_ci if (err) 1858c2ecf20Sopenharmony_ci goto out; 1868c2ecf20Sopenharmony_ci 1878c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "Connecting...\n"); 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); 1908c2ecf20Sopenharmony_ci if (err) 1918c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 1928c2ecf20Sopenharmony_ci "Error switching to connected state!"); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "Connected? %d\n", err); 1958c2ecf20Sopenharmony_ciout: 1968c2ecf20Sopenharmony_ci mutex_unlock(&pdev->dev_lock); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci kfree(magic); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci return err; 2018c2ecf20Sopenharmony_ci} 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic int xen_pcibk_publish_pci_dev(struct xen_pcibk_device *pdev, 2048c2ecf20Sopenharmony_ci unsigned int domain, unsigned int bus, 2058c2ecf20Sopenharmony_ci unsigned int devfn, unsigned int devid) 2068c2ecf20Sopenharmony_ci{ 2078c2ecf20Sopenharmony_ci int err; 2088c2ecf20Sopenharmony_ci int len; 2098c2ecf20Sopenharmony_ci char str[64]; 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci len = snprintf(str, sizeof(str), "vdev-%d", devid); 2128c2ecf20Sopenharmony_ci if (unlikely(len >= (sizeof(str) - 1))) { 2138c2ecf20Sopenharmony_ci err = -ENOMEM; 2148c2ecf20Sopenharmony_ci goto out; 2158c2ecf20Sopenharmony_ci } 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci /* Note: The PV protocol uses %02x, don't change it */ 2188c2ecf20Sopenharmony_ci err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, 2198c2ecf20Sopenharmony_ci "%04x:%02x:%02x.%02x", domain, bus, 2208c2ecf20Sopenharmony_ci PCI_SLOT(devfn), PCI_FUNC(devfn)); 2218c2ecf20Sopenharmony_ci 2228c2ecf20Sopenharmony_ciout: 2238c2ecf20Sopenharmony_ci return err; 2248c2ecf20Sopenharmony_ci} 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_cistatic int xen_pcibk_export_device(struct xen_pcibk_device *pdev, 2278c2ecf20Sopenharmony_ci int domain, int bus, int slot, int func, 2288c2ecf20Sopenharmony_ci int devid) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci struct pci_dev *dev; 2318c2ecf20Sopenharmony_ci int err = 0; 2328c2ecf20Sopenharmony_ci 2338c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "exporting dom %x bus %x slot %x func %x\n", 2348c2ecf20Sopenharmony_ci domain, bus, slot, func); 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci dev = pcistub_get_pci_dev_by_slot(pdev, domain, bus, slot, func); 2378c2ecf20Sopenharmony_ci if (!dev) { 2388c2ecf20Sopenharmony_ci err = -EINVAL; 2398c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 2408c2ecf20Sopenharmony_ci "Couldn't locate PCI device " 2418c2ecf20Sopenharmony_ci "(%04x:%02x:%02x.%d)! " 2428c2ecf20Sopenharmony_ci "perhaps already in-use?", 2438c2ecf20Sopenharmony_ci domain, bus, slot, func); 2448c2ecf20Sopenharmony_ci goto out; 2458c2ecf20Sopenharmony_ci } 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci err = xen_pcibk_add_pci_dev(pdev, dev, devid, 2488c2ecf20Sopenharmony_ci xen_pcibk_publish_pci_dev); 2498c2ecf20Sopenharmony_ci if (err) 2508c2ecf20Sopenharmony_ci goto out; 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci dev_info(&dev->dev, "registering for %d\n", pdev->xdev->otherend_id); 2538c2ecf20Sopenharmony_ci if (xen_register_device_domain_owner(dev, 2548c2ecf20Sopenharmony_ci pdev->xdev->otherend_id) != 0) { 2558c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Stealing ownership from dom%d.\n", 2568c2ecf20Sopenharmony_ci xen_find_device_domain_owner(dev)); 2578c2ecf20Sopenharmony_ci xen_unregister_device_domain_owner(dev); 2588c2ecf20Sopenharmony_ci xen_register_device_domain_owner(dev, pdev->xdev->otherend_id); 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci /* TODO: It'd be nice to export a bridge and have all of its children 2628c2ecf20Sopenharmony_ci * get exported with it. This may be best done in xend (which will 2638c2ecf20Sopenharmony_ci * have to calculate resource usage anyway) but we probably want to 2648c2ecf20Sopenharmony_ci * put something in here to ensure that if a bridge gets given to a 2658c2ecf20Sopenharmony_ci * driver domain, that all devices under that bridge are not given 2668c2ecf20Sopenharmony_ci * to other driver domains (as he who controls the bridge can disable 2678c2ecf20Sopenharmony_ci * it and stop the other devices from working). 2688c2ecf20Sopenharmony_ci */ 2698c2ecf20Sopenharmony_ciout: 2708c2ecf20Sopenharmony_ci return err; 2718c2ecf20Sopenharmony_ci} 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_cistatic int xen_pcibk_remove_device(struct xen_pcibk_device *pdev, 2748c2ecf20Sopenharmony_ci int domain, int bus, int slot, int func) 2758c2ecf20Sopenharmony_ci{ 2768c2ecf20Sopenharmony_ci int err = 0; 2778c2ecf20Sopenharmony_ci struct pci_dev *dev; 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "removing dom %x bus %x slot %x func %x\n", 2808c2ecf20Sopenharmony_ci domain, bus, slot, func); 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_ci dev = xen_pcibk_get_pci_dev(pdev, domain, bus, PCI_DEVFN(slot, func)); 2838c2ecf20Sopenharmony_ci if (!dev) { 2848c2ecf20Sopenharmony_ci err = -EINVAL; 2858c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "Couldn't locate PCI device " 2868c2ecf20Sopenharmony_ci "(%04x:%02x:%02x.%d)! not owned by this domain\n", 2878c2ecf20Sopenharmony_ci domain, bus, slot, func); 2888c2ecf20Sopenharmony_ci goto out; 2898c2ecf20Sopenharmony_ci } 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ci dev_dbg(&dev->dev, "unregistering for %d\n", pdev->xdev->otherend_id); 2928c2ecf20Sopenharmony_ci xen_unregister_device_domain_owner(dev); 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci /* N.B. This ends up calling pcistub_put_pci_dev which ends up 2958c2ecf20Sopenharmony_ci * doing the FLR. */ 2968c2ecf20Sopenharmony_ci xen_pcibk_release_pci_dev(pdev, dev, true /* use the lock. */); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciout: 2998c2ecf20Sopenharmony_ci return err; 3008c2ecf20Sopenharmony_ci} 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_cistatic int xen_pcibk_publish_pci_root(struct xen_pcibk_device *pdev, 3038c2ecf20Sopenharmony_ci unsigned int domain, unsigned int bus) 3048c2ecf20Sopenharmony_ci{ 3058c2ecf20Sopenharmony_ci unsigned int d, b; 3068c2ecf20Sopenharmony_ci int i, root_num, len, err; 3078c2ecf20Sopenharmony_ci char str[64]; 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "Publishing pci roots\n"); 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 3128c2ecf20Sopenharmony_ci "root_num", "%d", &root_num); 3138c2ecf20Sopenharmony_ci if (err == 0 || err == -ENOENT) 3148c2ecf20Sopenharmony_ci root_num = 0; 3158c2ecf20Sopenharmony_ci else if (err < 0) 3168c2ecf20Sopenharmony_ci goto out; 3178c2ecf20Sopenharmony_ci 3188c2ecf20Sopenharmony_ci /* Verify that we haven't already published this pci root */ 3198c2ecf20Sopenharmony_ci for (i = 0; i < root_num; i++) { 3208c2ecf20Sopenharmony_ci len = snprintf(str, sizeof(str), "root-%d", i); 3218c2ecf20Sopenharmony_ci if (unlikely(len >= (sizeof(str) - 1))) { 3228c2ecf20Sopenharmony_ci err = -ENOMEM; 3238c2ecf20Sopenharmony_ci goto out; 3248c2ecf20Sopenharmony_ci } 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 3278c2ecf20Sopenharmony_ci str, "%x:%x", &d, &b); 3288c2ecf20Sopenharmony_ci if (err < 0) 3298c2ecf20Sopenharmony_ci goto out; 3308c2ecf20Sopenharmony_ci if (err != 2) { 3318c2ecf20Sopenharmony_ci err = -EINVAL; 3328c2ecf20Sopenharmony_ci goto out; 3338c2ecf20Sopenharmony_ci } 3348c2ecf20Sopenharmony_ci 3358c2ecf20Sopenharmony_ci if (d == domain && b == bus) { 3368c2ecf20Sopenharmony_ci err = 0; 3378c2ecf20Sopenharmony_ci goto out; 3388c2ecf20Sopenharmony_ci } 3398c2ecf20Sopenharmony_ci } 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci len = snprintf(str, sizeof(str), "root-%d", root_num); 3428c2ecf20Sopenharmony_ci if (unlikely(len >= (sizeof(str) - 1))) { 3438c2ecf20Sopenharmony_ci err = -ENOMEM; 3448c2ecf20Sopenharmony_ci goto out; 3458c2ecf20Sopenharmony_ci } 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "writing root %d at %04x:%02x\n", 3488c2ecf20Sopenharmony_ci root_num, domain, bus); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, str, 3518c2ecf20Sopenharmony_ci "%04x:%02x", domain, bus); 3528c2ecf20Sopenharmony_ci if (err) 3538c2ecf20Sopenharmony_ci goto out; 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, 3568c2ecf20Sopenharmony_ci "root_num", "%d", (root_num + 1)); 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_ciout: 3598c2ecf20Sopenharmony_ci return err; 3608c2ecf20Sopenharmony_ci} 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_cistatic int xen_pcibk_reconfigure(struct xen_pcibk_device *pdev, 3638c2ecf20Sopenharmony_ci enum xenbus_state state) 3648c2ecf20Sopenharmony_ci{ 3658c2ecf20Sopenharmony_ci int err = 0; 3668c2ecf20Sopenharmony_ci int num_devs; 3678c2ecf20Sopenharmony_ci int domain, bus, slot, func; 3688c2ecf20Sopenharmony_ci unsigned int substate; 3698c2ecf20Sopenharmony_ci int i, len; 3708c2ecf20Sopenharmony_ci char state_str[64]; 3718c2ecf20Sopenharmony_ci char dev_str[64]; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "Reconfiguring device ...\n"); 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci mutex_lock(&pdev->dev_lock); 3778c2ecf20Sopenharmony_ci if (xenbus_read_driver_state(pdev->xdev->nodename) != state) 3788c2ecf20Sopenharmony_ci goto out; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", 3818c2ecf20Sopenharmony_ci &num_devs); 3828c2ecf20Sopenharmony_ci if (err != 1) { 3838c2ecf20Sopenharmony_ci if (err >= 0) 3848c2ecf20Sopenharmony_ci err = -EINVAL; 3858c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 3868c2ecf20Sopenharmony_ci "Error reading number of devices"); 3878c2ecf20Sopenharmony_ci goto out; 3888c2ecf20Sopenharmony_ci } 3898c2ecf20Sopenharmony_ci 3908c2ecf20Sopenharmony_ci for (i = 0; i < num_devs; i++) { 3918c2ecf20Sopenharmony_ci len = snprintf(state_str, sizeof(state_str), "state-%d", i); 3928c2ecf20Sopenharmony_ci if (unlikely(len >= (sizeof(state_str) - 1))) { 3938c2ecf20Sopenharmony_ci err = -ENOMEM; 3948c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 3958c2ecf20Sopenharmony_ci "String overflow while reading " 3968c2ecf20Sopenharmony_ci "configuration"); 3978c2ecf20Sopenharmony_ci goto out; 3988c2ecf20Sopenharmony_ci } 3998c2ecf20Sopenharmony_ci substate = xenbus_read_unsigned(pdev->xdev->nodename, state_str, 4008c2ecf20Sopenharmony_ci XenbusStateUnknown); 4018c2ecf20Sopenharmony_ci 4028c2ecf20Sopenharmony_ci switch (substate) { 4038c2ecf20Sopenharmony_ci case XenbusStateInitialising: 4048c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "Attaching dev-%d ...\n", i); 4058c2ecf20Sopenharmony_ci 4068c2ecf20Sopenharmony_ci len = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); 4078c2ecf20Sopenharmony_ci if (unlikely(len >= (sizeof(dev_str) - 1))) { 4088c2ecf20Sopenharmony_ci err = -ENOMEM; 4098c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 4108c2ecf20Sopenharmony_ci "String overflow while " 4118c2ecf20Sopenharmony_ci "reading configuration"); 4128c2ecf20Sopenharmony_ci goto out; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 4158c2ecf20Sopenharmony_ci dev_str, "%x:%x:%x.%x", 4168c2ecf20Sopenharmony_ci &domain, &bus, &slot, &func); 4178c2ecf20Sopenharmony_ci if (err < 0) { 4188c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 4198c2ecf20Sopenharmony_ci "Error reading device " 4208c2ecf20Sopenharmony_ci "configuration"); 4218c2ecf20Sopenharmony_ci goto out; 4228c2ecf20Sopenharmony_ci } 4238c2ecf20Sopenharmony_ci if (err != 4) { 4248c2ecf20Sopenharmony_ci err = -EINVAL; 4258c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 4268c2ecf20Sopenharmony_ci "Error parsing pci device " 4278c2ecf20Sopenharmony_ci "configuration"); 4288c2ecf20Sopenharmony_ci goto out; 4298c2ecf20Sopenharmony_ci } 4308c2ecf20Sopenharmony_ci 4318c2ecf20Sopenharmony_ci err = xen_pcibk_export_device(pdev, domain, bus, slot, 4328c2ecf20Sopenharmony_ci func, i); 4338c2ecf20Sopenharmony_ci if (err) 4348c2ecf20Sopenharmony_ci goto out; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci /* Publish pci roots. */ 4378c2ecf20Sopenharmony_ci err = xen_pcibk_publish_pci_roots(pdev, 4388c2ecf20Sopenharmony_ci xen_pcibk_publish_pci_root); 4398c2ecf20Sopenharmony_ci if (err) { 4408c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 4418c2ecf20Sopenharmony_ci "Error while publish PCI root" 4428c2ecf20Sopenharmony_ci "buses for frontend"); 4438c2ecf20Sopenharmony_ci goto out; 4448c2ecf20Sopenharmony_ci } 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, 4478c2ecf20Sopenharmony_ci state_str, "%d", 4488c2ecf20Sopenharmony_ci XenbusStateInitialised); 4498c2ecf20Sopenharmony_ci if (err) { 4508c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 4518c2ecf20Sopenharmony_ci "Error switching substate of " 4528c2ecf20Sopenharmony_ci "dev-%d\n", i); 4538c2ecf20Sopenharmony_ci goto out; 4548c2ecf20Sopenharmony_ci } 4558c2ecf20Sopenharmony_ci break; 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci case XenbusStateClosing: 4588c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "Detaching dev-%d ...\n", i); 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci len = snprintf(dev_str, sizeof(dev_str), "vdev-%d", i); 4618c2ecf20Sopenharmony_ci if (unlikely(len >= (sizeof(dev_str) - 1))) { 4628c2ecf20Sopenharmony_ci err = -ENOMEM; 4638c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 4648c2ecf20Sopenharmony_ci "String overflow while " 4658c2ecf20Sopenharmony_ci "reading configuration"); 4668c2ecf20Sopenharmony_ci goto out; 4678c2ecf20Sopenharmony_ci } 4688c2ecf20Sopenharmony_ci err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, 4698c2ecf20Sopenharmony_ci dev_str, "%x:%x:%x.%x", 4708c2ecf20Sopenharmony_ci &domain, &bus, &slot, &func); 4718c2ecf20Sopenharmony_ci if (err < 0) { 4728c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 4738c2ecf20Sopenharmony_ci "Error reading device " 4748c2ecf20Sopenharmony_ci "configuration"); 4758c2ecf20Sopenharmony_ci goto out; 4768c2ecf20Sopenharmony_ci } 4778c2ecf20Sopenharmony_ci if (err != 4) { 4788c2ecf20Sopenharmony_ci err = -EINVAL; 4798c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 4808c2ecf20Sopenharmony_ci "Error parsing pci device " 4818c2ecf20Sopenharmony_ci "configuration"); 4828c2ecf20Sopenharmony_ci goto out; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci err = xen_pcibk_remove_device(pdev, domain, bus, slot, 4868c2ecf20Sopenharmony_ci func); 4878c2ecf20Sopenharmony_ci if (err) 4888c2ecf20Sopenharmony_ci goto out; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* TODO: If at some point we implement support for pci 4918c2ecf20Sopenharmony_ci * root hot-remove on pcifront side, we'll need to 4928c2ecf20Sopenharmony_ci * remove unnecessary xenstore nodes of pci roots here. 4938c2ecf20Sopenharmony_ci */ 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci break; 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci default: 4988c2ecf20Sopenharmony_ci break; 4998c2ecf20Sopenharmony_ci } 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (state != XenbusStateReconfiguring) 5038c2ecf20Sopenharmony_ci /* Make sure we only reconfigure once. */ 5048c2ecf20Sopenharmony_ci goto out; 5058c2ecf20Sopenharmony_ci 5068c2ecf20Sopenharmony_ci err = xenbus_switch_state(pdev->xdev, XenbusStateReconfigured); 5078c2ecf20Sopenharmony_ci if (err) { 5088c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 5098c2ecf20Sopenharmony_ci "Error switching to reconfigured state!"); 5108c2ecf20Sopenharmony_ci goto out; 5118c2ecf20Sopenharmony_ci } 5128c2ecf20Sopenharmony_ci 5138c2ecf20Sopenharmony_ciout: 5148c2ecf20Sopenharmony_ci mutex_unlock(&pdev->dev_lock); 5158c2ecf20Sopenharmony_ci return 0; 5168c2ecf20Sopenharmony_ci} 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_cistatic void xen_pcibk_frontend_changed(struct xenbus_device *xdev, 5198c2ecf20Sopenharmony_ci enum xenbus_state fe_state) 5208c2ecf20Sopenharmony_ci{ 5218c2ecf20Sopenharmony_ci struct xen_pcibk_device *pdev = dev_get_drvdata(&xdev->dev); 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci dev_dbg(&xdev->dev, "fe state changed %d\n", fe_state); 5248c2ecf20Sopenharmony_ci 5258c2ecf20Sopenharmony_ci switch (fe_state) { 5268c2ecf20Sopenharmony_ci case XenbusStateInitialised: 5278c2ecf20Sopenharmony_ci xen_pcibk_attach(pdev); 5288c2ecf20Sopenharmony_ci break; 5298c2ecf20Sopenharmony_ci 5308c2ecf20Sopenharmony_ci case XenbusStateReconfiguring: 5318c2ecf20Sopenharmony_ci xen_pcibk_reconfigure(pdev, XenbusStateReconfiguring); 5328c2ecf20Sopenharmony_ci break; 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci case XenbusStateConnected: 5358c2ecf20Sopenharmony_ci /* pcifront switched its state from reconfiguring to connected. 5368c2ecf20Sopenharmony_ci * Then switch to connected state. 5378c2ecf20Sopenharmony_ci */ 5388c2ecf20Sopenharmony_ci xenbus_switch_state(xdev, XenbusStateConnected); 5398c2ecf20Sopenharmony_ci break; 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci case XenbusStateClosing: 5428c2ecf20Sopenharmony_ci xen_pcibk_disconnect(pdev); 5438c2ecf20Sopenharmony_ci xenbus_switch_state(xdev, XenbusStateClosing); 5448c2ecf20Sopenharmony_ci break; 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci case XenbusStateClosed: 5478c2ecf20Sopenharmony_ci xen_pcibk_disconnect(pdev); 5488c2ecf20Sopenharmony_ci xenbus_switch_state(xdev, XenbusStateClosed); 5498c2ecf20Sopenharmony_ci if (xenbus_dev_is_online(xdev)) 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci fallthrough; /* if not online */ 5528c2ecf20Sopenharmony_ci case XenbusStateUnknown: 5538c2ecf20Sopenharmony_ci dev_dbg(&xdev->dev, "frontend is gone! unregister device\n"); 5548c2ecf20Sopenharmony_ci device_unregister(&xdev->dev); 5558c2ecf20Sopenharmony_ci break; 5568c2ecf20Sopenharmony_ci 5578c2ecf20Sopenharmony_ci default: 5588c2ecf20Sopenharmony_ci break; 5598c2ecf20Sopenharmony_ci } 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic int xen_pcibk_setup_backend(struct xen_pcibk_device *pdev) 5638c2ecf20Sopenharmony_ci{ 5648c2ecf20Sopenharmony_ci /* Get configuration from xend (if available now) */ 5658c2ecf20Sopenharmony_ci int domain, bus, slot, func; 5668c2ecf20Sopenharmony_ci int err = 0; 5678c2ecf20Sopenharmony_ci int i, num_devs; 5688c2ecf20Sopenharmony_ci char dev_str[64]; 5698c2ecf20Sopenharmony_ci char state_str[64]; 5708c2ecf20Sopenharmony_ci 5718c2ecf20Sopenharmony_ci mutex_lock(&pdev->dev_lock); 5728c2ecf20Sopenharmony_ci /* It's possible we could get the call to setup twice, so make sure 5738c2ecf20Sopenharmony_ci * we're not already connected. 5748c2ecf20Sopenharmony_ci */ 5758c2ecf20Sopenharmony_ci if (xenbus_read_driver_state(pdev->xdev->nodename) != 5768c2ecf20Sopenharmony_ci XenbusStateInitWait) 5778c2ecf20Sopenharmony_ci goto out; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci dev_dbg(&pdev->xdev->dev, "getting be setup\n"); 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, "num_devs", "%d", 5828c2ecf20Sopenharmony_ci &num_devs); 5838c2ecf20Sopenharmony_ci if (err != 1) { 5848c2ecf20Sopenharmony_ci if (err >= 0) 5858c2ecf20Sopenharmony_ci err = -EINVAL; 5868c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 5878c2ecf20Sopenharmony_ci "Error reading number of devices"); 5888c2ecf20Sopenharmony_ci goto out; 5898c2ecf20Sopenharmony_ci } 5908c2ecf20Sopenharmony_ci 5918c2ecf20Sopenharmony_ci for (i = 0; i < num_devs; i++) { 5928c2ecf20Sopenharmony_ci int l = snprintf(dev_str, sizeof(dev_str), "dev-%d", i); 5938c2ecf20Sopenharmony_ci if (unlikely(l >= (sizeof(dev_str) - 1))) { 5948c2ecf20Sopenharmony_ci err = -ENOMEM; 5958c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 5968c2ecf20Sopenharmony_ci "String overflow while reading " 5978c2ecf20Sopenharmony_ci "configuration"); 5988c2ecf20Sopenharmony_ci goto out; 5998c2ecf20Sopenharmony_ci } 6008c2ecf20Sopenharmony_ci 6018c2ecf20Sopenharmony_ci err = xenbus_scanf(XBT_NIL, pdev->xdev->nodename, dev_str, 6028c2ecf20Sopenharmony_ci "%x:%x:%x.%x", &domain, &bus, &slot, &func); 6038c2ecf20Sopenharmony_ci if (err < 0) { 6048c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 6058c2ecf20Sopenharmony_ci "Error reading device configuration"); 6068c2ecf20Sopenharmony_ci goto out; 6078c2ecf20Sopenharmony_ci } 6088c2ecf20Sopenharmony_ci if (err != 4) { 6098c2ecf20Sopenharmony_ci err = -EINVAL; 6108c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 6118c2ecf20Sopenharmony_ci "Error parsing pci device " 6128c2ecf20Sopenharmony_ci "configuration"); 6138c2ecf20Sopenharmony_ci goto out; 6148c2ecf20Sopenharmony_ci } 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci err = xen_pcibk_export_device(pdev, domain, bus, slot, func, i); 6178c2ecf20Sopenharmony_ci if (err) 6188c2ecf20Sopenharmony_ci goto out; 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci /* Switch substate of this device. */ 6218c2ecf20Sopenharmony_ci l = snprintf(state_str, sizeof(state_str), "state-%d", i); 6228c2ecf20Sopenharmony_ci if (unlikely(l >= (sizeof(state_str) - 1))) { 6238c2ecf20Sopenharmony_ci err = -ENOMEM; 6248c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 6258c2ecf20Sopenharmony_ci "String overflow while reading " 6268c2ecf20Sopenharmony_ci "configuration"); 6278c2ecf20Sopenharmony_ci goto out; 6288c2ecf20Sopenharmony_ci } 6298c2ecf20Sopenharmony_ci err = xenbus_printf(XBT_NIL, pdev->xdev->nodename, state_str, 6308c2ecf20Sopenharmony_ci "%d", XenbusStateInitialised); 6318c2ecf20Sopenharmony_ci if (err) { 6328c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, "Error switching " 6338c2ecf20Sopenharmony_ci "substate of dev-%d\n", i); 6348c2ecf20Sopenharmony_ci goto out; 6358c2ecf20Sopenharmony_ci } 6368c2ecf20Sopenharmony_ci } 6378c2ecf20Sopenharmony_ci 6388c2ecf20Sopenharmony_ci err = xen_pcibk_publish_pci_roots(pdev, xen_pcibk_publish_pci_root); 6398c2ecf20Sopenharmony_ci if (err) { 6408c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 6418c2ecf20Sopenharmony_ci "Error while publish PCI root buses " 6428c2ecf20Sopenharmony_ci "for frontend"); 6438c2ecf20Sopenharmony_ci goto out; 6448c2ecf20Sopenharmony_ci } 6458c2ecf20Sopenharmony_ci 6468c2ecf20Sopenharmony_ci err = xenbus_switch_state(pdev->xdev, XenbusStateInitialised); 6478c2ecf20Sopenharmony_ci if (err) 6488c2ecf20Sopenharmony_ci xenbus_dev_fatal(pdev->xdev, err, 6498c2ecf20Sopenharmony_ci "Error switching to initialised state!"); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ciout: 6528c2ecf20Sopenharmony_ci mutex_unlock(&pdev->dev_lock); 6538c2ecf20Sopenharmony_ci if (!err) 6548c2ecf20Sopenharmony_ci /* see if pcifront is already configured (if not, we'll wait) */ 6558c2ecf20Sopenharmony_ci xen_pcibk_attach(pdev); 6568c2ecf20Sopenharmony_ci return err; 6578c2ecf20Sopenharmony_ci} 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_cistatic void xen_pcibk_be_watch(struct xenbus_watch *watch, 6608c2ecf20Sopenharmony_ci const char *path, const char *token) 6618c2ecf20Sopenharmony_ci{ 6628c2ecf20Sopenharmony_ci struct xen_pcibk_device *pdev = 6638c2ecf20Sopenharmony_ci container_of(watch, struct xen_pcibk_device, be_watch); 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci switch (xenbus_read_driver_state(pdev->xdev->nodename)) { 6668c2ecf20Sopenharmony_ci case XenbusStateInitWait: 6678c2ecf20Sopenharmony_ci xen_pcibk_setup_backend(pdev); 6688c2ecf20Sopenharmony_ci break; 6698c2ecf20Sopenharmony_ci 6708c2ecf20Sopenharmony_ci case XenbusStateInitialised: 6718c2ecf20Sopenharmony_ci /* 6728c2ecf20Sopenharmony_ci * We typically move to Initialised when the first device was 6738c2ecf20Sopenharmony_ci * added. Hence subsequent devices getting added may need 6748c2ecf20Sopenharmony_ci * reconfiguring. 6758c2ecf20Sopenharmony_ci */ 6768c2ecf20Sopenharmony_ci xen_pcibk_reconfigure(pdev, XenbusStateInitialised); 6778c2ecf20Sopenharmony_ci break; 6788c2ecf20Sopenharmony_ci 6798c2ecf20Sopenharmony_ci default: 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci } 6828c2ecf20Sopenharmony_ci} 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_cistatic int xen_pcibk_xenbus_probe(struct xenbus_device *dev, 6858c2ecf20Sopenharmony_ci const struct xenbus_device_id *id) 6868c2ecf20Sopenharmony_ci{ 6878c2ecf20Sopenharmony_ci int err = 0; 6888c2ecf20Sopenharmony_ci struct xen_pcibk_device *pdev = alloc_pdev(dev); 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci if (pdev == NULL) { 6918c2ecf20Sopenharmony_ci err = -ENOMEM; 6928c2ecf20Sopenharmony_ci xenbus_dev_fatal(dev, err, 6938c2ecf20Sopenharmony_ci "Error allocating xen_pcibk_device struct"); 6948c2ecf20Sopenharmony_ci goto out; 6958c2ecf20Sopenharmony_ci } 6968c2ecf20Sopenharmony_ci 6978c2ecf20Sopenharmony_ci /* wait for xend to configure us */ 6988c2ecf20Sopenharmony_ci err = xenbus_switch_state(dev, XenbusStateInitWait); 6998c2ecf20Sopenharmony_ci if (err) 7008c2ecf20Sopenharmony_ci goto out; 7018c2ecf20Sopenharmony_ci 7028c2ecf20Sopenharmony_ci /* watch the backend node for backend configuration information */ 7038c2ecf20Sopenharmony_ci err = xenbus_watch_path(dev, dev->nodename, &pdev->be_watch, 7048c2ecf20Sopenharmony_ci NULL, xen_pcibk_be_watch); 7058c2ecf20Sopenharmony_ci if (err) 7068c2ecf20Sopenharmony_ci goto out; 7078c2ecf20Sopenharmony_ci 7088c2ecf20Sopenharmony_ci pdev->be_watching = 1; 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* We need to force a call to our callback here in case 7118c2ecf20Sopenharmony_ci * xend already configured us! 7128c2ecf20Sopenharmony_ci */ 7138c2ecf20Sopenharmony_ci xen_pcibk_be_watch(&pdev->be_watch, NULL, NULL); 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ciout: 7168c2ecf20Sopenharmony_ci return err; 7178c2ecf20Sopenharmony_ci} 7188c2ecf20Sopenharmony_ci 7198c2ecf20Sopenharmony_cistatic int xen_pcibk_xenbus_remove(struct xenbus_device *dev) 7208c2ecf20Sopenharmony_ci{ 7218c2ecf20Sopenharmony_ci struct xen_pcibk_device *pdev = dev_get_drvdata(&dev->dev); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci if (pdev != NULL) 7248c2ecf20Sopenharmony_ci free_pdev(pdev); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci return 0; 7278c2ecf20Sopenharmony_ci} 7288c2ecf20Sopenharmony_ci 7298c2ecf20Sopenharmony_cistatic const struct xenbus_device_id xen_pcibk_ids[] = { 7308c2ecf20Sopenharmony_ci {"pci"}, 7318c2ecf20Sopenharmony_ci {""}, 7328c2ecf20Sopenharmony_ci}; 7338c2ecf20Sopenharmony_ci 7348c2ecf20Sopenharmony_cistatic struct xenbus_driver xen_pcibk_driver = { 7358c2ecf20Sopenharmony_ci .name = DRV_NAME, 7368c2ecf20Sopenharmony_ci .ids = xen_pcibk_ids, 7378c2ecf20Sopenharmony_ci .probe = xen_pcibk_xenbus_probe, 7388c2ecf20Sopenharmony_ci .remove = xen_pcibk_xenbus_remove, 7398c2ecf20Sopenharmony_ci .otherend_changed = xen_pcibk_frontend_changed, 7408c2ecf20Sopenharmony_ci}; 7418c2ecf20Sopenharmony_ci 7428c2ecf20Sopenharmony_ciconst struct xen_pcibk_backend *__read_mostly xen_pcibk_backend; 7438c2ecf20Sopenharmony_ci 7448c2ecf20Sopenharmony_ciint __init xen_pcibk_xenbus_register(void) 7458c2ecf20Sopenharmony_ci{ 7468c2ecf20Sopenharmony_ci xen_pcibk_backend = &xen_pcibk_vpci_backend; 7478c2ecf20Sopenharmony_ci if (passthrough) 7488c2ecf20Sopenharmony_ci xen_pcibk_backend = &xen_pcibk_passthrough_backend; 7498c2ecf20Sopenharmony_ci pr_info("backend is %s\n", xen_pcibk_backend->name); 7508c2ecf20Sopenharmony_ci return xenbus_register_backend(&xen_pcibk_driver); 7518c2ecf20Sopenharmony_ci} 7528c2ecf20Sopenharmony_ci 7538c2ecf20Sopenharmony_civoid __exit xen_pcibk_xenbus_unregister(void) 7548c2ecf20Sopenharmony_ci{ 7558c2ecf20Sopenharmony_ci xenbus_unregister_driver(&xen_pcibk_driver); 7568c2ecf20Sopenharmony_ci} 757