1*956a9202SRyan Wilson /* 2*956a9202SRyan Wilson * Xen PCI Frontend. 3*956a9202SRyan Wilson * 4*956a9202SRyan Wilson * Author: Ryan Wilson <hap9@epoch.ncsc.mil> 5*956a9202SRyan Wilson */ 6*956a9202SRyan Wilson #include <linux/module.h> 7*956a9202SRyan Wilson #include <linux/init.h> 8*956a9202SRyan Wilson #include <linux/mm.h> 9*956a9202SRyan Wilson #include <xen/xenbus.h> 10*956a9202SRyan Wilson #include <xen/events.h> 11*956a9202SRyan Wilson #include <xen/grant_table.h> 12*956a9202SRyan Wilson #include <xen/page.h> 13*956a9202SRyan Wilson #include <linux/spinlock.h> 14*956a9202SRyan Wilson #include <linux/pci.h> 15*956a9202SRyan Wilson #include <linux/msi.h> 16*956a9202SRyan Wilson #include <xen/xenbus.h> 17*956a9202SRyan Wilson #include <xen/interface/io/pciif.h> 18*956a9202SRyan Wilson #include <asm/xen/pci.h> 19*956a9202SRyan Wilson #include <linux/interrupt.h> 20*956a9202SRyan Wilson #include <asm/atomic.h> 21*956a9202SRyan Wilson #include <linux/workqueue.h> 22*956a9202SRyan Wilson #include <linux/bitops.h> 23*956a9202SRyan Wilson #include <linux/time.h> 24*956a9202SRyan Wilson 25*956a9202SRyan Wilson #define INVALID_GRANT_REF (0) 26*956a9202SRyan Wilson #define INVALID_EVTCHN (-1) 27*956a9202SRyan Wilson 28*956a9202SRyan Wilson struct pci_bus_entry { 29*956a9202SRyan Wilson struct list_head list; 30*956a9202SRyan Wilson struct pci_bus *bus; 31*956a9202SRyan Wilson }; 32*956a9202SRyan Wilson 33*956a9202SRyan Wilson #define _PDEVB_op_active (0) 34*956a9202SRyan Wilson #define PDEVB_op_active (1 << (_PDEVB_op_active)) 35*956a9202SRyan Wilson 36*956a9202SRyan Wilson struct pcifront_device { 37*956a9202SRyan Wilson struct xenbus_device *xdev; 38*956a9202SRyan Wilson struct list_head root_buses; 39*956a9202SRyan Wilson 40*956a9202SRyan Wilson int evtchn; 41*956a9202SRyan Wilson int gnt_ref; 42*956a9202SRyan Wilson 43*956a9202SRyan Wilson int irq; 44*956a9202SRyan Wilson 45*956a9202SRyan Wilson /* Lock this when doing any operations in sh_info */ 46*956a9202SRyan Wilson spinlock_t sh_info_lock; 47*956a9202SRyan Wilson struct xen_pci_sharedinfo *sh_info; 48*956a9202SRyan Wilson struct work_struct op_work; 49*956a9202SRyan Wilson unsigned long flags; 50*956a9202SRyan Wilson 51*956a9202SRyan Wilson }; 52*956a9202SRyan Wilson 53*956a9202SRyan Wilson struct pcifront_sd { 54*956a9202SRyan Wilson int domain; 55*956a9202SRyan Wilson struct pcifront_device *pdev; 56*956a9202SRyan Wilson }; 57*956a9202SRyan Wilson 58*956a9202SRyan Wilson static inline struct pcifront_device * 59*956a9202SRyan Wilson pcifront_get_pdev(struct pcifront_sd *sd) 60*956a9202SRyan Wilson { 61*956a9202SRyan Wilson return sd->pdev; 62*956a9202SRyan Wilson } 63*956a9202SRyan Wilson 64*956a9202SRyan Wilson static inline void pcifront_init_sd(struct pcifront_sd *sd, 65*956a9202SRyan Wilson unsigned int domain, unsigned int bus, 66*956a9202SRyan Wilson struct pcifront_device *pdev) 67*956a9202SRyan Wilson { 68*956a9202SRyan Wilson sd->domain = domain; 69*956a9202SRyan Wilson sd->pdev = pdev; 70*956a9202SRyan Wilson } 71*956a9202SRyan Wilson 72*956a9202SRyan Wilson static DEFINE_SPINLOCK(pcifront_dev_lock); 73*956a9202SRyan Wilson static struct pcifront_device *pcifront_dev; 74*956a9202SRyan Wilson 75*956a9202SRyan Wilson static int verbose_request; 76*956a9202SRyan Wilson module_param(verbose_request, int, 0644); 77*956a9202SRyan Wilson 78*956a9202SRyan Wilson static int errno_to_pcibios_err(int errno) 79*956a9202SRyan Wilson { 80*956a9202SRyan Wilson switch (errno) { 81*956a9202SRyan Wilson case XEN_PCI_ERR_success: 82*956a9202SRyan Wilson return PCIBIOS_SUCCESSFUL; 83*956a9202SRyan Wilson 84*956a9202SRyan Wilson case XEN_PCI_ERR_dev_not_found: 85*956a9202SRyan Wilson return PCIBIOS_DEVICE_NOT_FOUND; 86*956a9202SRyan Wilson 87*956a9202SRyan Wilson case XEN_PCI_ERR_invalid_offset: 88*956a9202SRyan Wilson case XEN_PCI_ERR_op_failed: 89*956a9202SRyan Wilson return PCIBIOS_BAD_REGISTER_NUMBER; 90*956a9202SRyan Wilson 91*956a9202SRyan Wilson case XEN_PCI_ERR_not_implemented: 92*956a9202SRyan Wilson return PCIBIOS_FUNC_NOT_SUPPORTED; 93*956a9202SRyan Wilson 94*956a9202SRyan Wilson case XEN_PCI_ERR_access_denied: 95*956a9202SRyan Wilson return PCIBIOS_SET_FAILED; 96*956a9202SRyan Wilson } 97*956a9202SRyan Wilson return errno; 98*956a9202SRyan Wilson } 99*956a9202SRyan Wilson 100*956a9202SRyan Wilson static inline void schedule_pcifront_aer_op(struct pcifront_device *pdev) 101*956a9202SRyan Wilson { 102*956a9202SRyan Wilson if (test_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags) 103*956a9202SRyan Wilson && !test_and_set_bit(_PDEVB_op_active, &pdev->flags)) { 104*956a9202SRyan Wilson dev_dbg(&pdev->xdev->dev, "schedule aer frontend job\n"); 105*956a9202SRyan Wilson schedule_work(&pdev->op_work); 106*956a9202SRyan Wilson } 107*956a9202SRyan Wilson } 108*956a9202SRyan Wilson 109*956a9202SRyan Wilson static int do_pci_op(struct pcifront_device *pdev, struct xen_pci_op *op) 110*956a9202SRyan Wilson { 111*956a9202SRyan Wilson int err = 0; 112*956a9202SRyan Wilson struct xen_pci_op *active_op = &pdev->sh_info->op; 113*956a9202SRyan Wilson unsigned long irq_flags; 114*956a9202SRyan Wilson evtchn_port_t port = pdev->evtchn; 115*956a9202SRyan Wilson unsigned irq = pdev->irq; 116*956a9202SRyan Wilson s64 ns, ns_timeout; 117*956a9202SRyan Wilson struct timeval tv; 118*956a9202SRyan Wilson 119*956a9202SRyan Wilson spin_lock_irqsave(&pdev->sh_info_lock, irq_flags); 120*956a9202SRyan Wilson 121*956a9202SRyan Wilson memcpy(active_op, op, sizeof(struct xen_pci_op)); 122*956a9202SRyan Wilson 123*956a9202SRyan Wilson /* Go */ 124*956a9202SRyan Wilson wmb(); 125*956a9202SRyan Wilson set_bit(_XEN_PCIF_active, (unsigned long *)&pdev->sh_info->flags); 126*956a9202SRyan Wilson notify_remote_via_evtchn(port); 127*956a9202SRyan Wilson 128*956a9202SRyan Wilson /* 129*956a9202SRyan Wilson * We set a poll timeout of 3 seconds but give up on return after 130*956a9202SRyan Wilson * 2 seconds. It is better to time out too late rather than too early 131*956a9202SRyan Wilson * (in the latter case we end up continually re-executing poll() with a 132*956a9202SRyan Wilson * timeout in the past). 1s difference gives plenty of slack for error. 133*956a9202SRyan Wilson */ 134*956a9202SRyan Wilson do_gettimeofday(&tv); 135*956a9202SRyan Wilson ns_timeout = timeval_to_ns(&tv) + 2 * (s64)NSEC_PER_SEC; 136*956a9202SRyan Wilson 137*956a9202SRyan Wilson xen_clear_irq_pending(irq); 138*956a9202SRyan Wilson 139*956a9202SRyan Wilson while (test_bit(_XEN_PCIF_active, 140*956a9202SRyan Wilson (unsigned long *)&pdev->sh_info->flags)) { 141*956a9202SRyan Wilson xen_poll_irq_timeout(irq, jiffies + 3*HZ); 142*956a9202SRyan Wilson xen_clear_irq_pending(irq); 143*956a9202SRyan Wilson do_gettimeofday(&tv); 144*956a9202SRyan Wilson ns = timeval_to_ns(&tv); 145*956a9202SRyan Wilson if (ns > ns_timeout) { 146*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, 147*956a9202SRyan Wilson "pciback not responding!!!\n"); 148*956a9202SRyan Wilson clear_bit(_XEN_PCIF_active, 149*956a9202SRyan Wilson (unsigned long *)&pdev->sh_info->flags); 150*956a9202SRyan Wilson err = XEN_PCI_ERR_dev_not_found; 151*956a9202SRyan Wilson goto out; 152*956a9202SRyan Wilson } 153*956a9202SRyan Wilson } 154*956a9202SRyan Wilson 155*956a9202SRyan Wilson /* 156*956a9202SRyan Wilson * We might lose backend service request since we 157*956a9202SRyan Wilson * reuse same evtchn with pci_conf backend response. So re-schedule 158*956a9202SRyan Wilson * aer pcifront service. 159*956a9202SRyan Wilson */ 160*956a9202SRyan Wilson if (test_bit(_XEN_PCIB_active, 161*956a9202SRyan Wilson (unsigned long *)&pdev->sh_info->flags)) { 162*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, 163*956a9202SRyan Wilson "schedule aer pcifront service\n"); 164*956a9202SRyan Wilson schedule_pcifront_aer_op(pdev); 165*956a9202SRyan Wilson } 166*956a9202SRyan Wilson 167*956a9202SRyan Wilson memcpy(op, active_op, sizeof(struct xen_pci_op)); 168*956a9202SRyan Wilson 169*956a9202SRyan Wilson err = op->err; 170*956a9202SRyan Wilson out: 171*956a9202SRyan Wilson spin_unlock_irqrestore(&pdev->sh_info_lock, irq_flags); 172*956a9202SRyan Wilson return err; 173*956a9202SRyan Wilson } 174*956a9202SRyan Wilson 175*956a9202SRyan Wilson /* Access to this function is spinlocked in drivers/pci/access.c */ 176*956a9202SRyan Wilson static int pcifront_bus_read(struct pci_bus *bus, unsigned int devfn, 177*956a9202SRyan Wilson int where, int size, u32 *val) 178*956a9202SRyan Wilson { 179*956a9202SRyan Wilson int err = 0; 180*956a9202SRyan Wilson struct xen_pci_op op = { 181*956a9202SRyan Wilson .cmd = XEN_PCI_OP_conf_read, 182*956a9202SRyan Wilson .domain = pci_domain_nr(bus), 183*956a9202SRyan Wilson .bus = bus->number, 184*956a9202SRyan Wilson .devfn = devfn, 185*956a9202SRyan Wilson .offset = where, 186*956a9202SRyan Wilson .size = size, 187*956a9202SRyan Wilson }; 188*956a9202SRyan Wilson struct pcifront_sd *sd = bus->sysdata; 189*956a9202SRyan Wilson struct pcifront_device *pdev = pcifront_get_pdev(sd); 190*956a9202SRyan Wilson 191*956a9202SRyan Wilson if (verbose_request) 192*956a9202SRyan Wilson dev_info(&pdev->xdev->dev, 193*956a9202SRyan Wilson "read dev=%04x:%02x:%02x.%01x - offset %x size %d\n", 194*956a9202SRyan Wilson pci_domain_nr(bus), bus->number, PCI_SLOT(devfn), 195*956a9202SRyan Wilson PCI_FUNC(devfn), where, size); 196*956a9202SRyan Wilson 197*956a9202SRyan Wilson err = do_pci_op(pdev, &op); 198*956a9202SRyan Wilson 199*956a9202SRyan Wilson if (likely(!err)) { 200*956a9202SRyan Wilson if (verbose_request) 201*956a9202SRyan Wilson dev_info(&pdev->xdev->dev, "read got back value %x\n", 202*956a9202SRyan Wilson op.value); 203*956a9202SRyan Wilson 204*956a9202SRyan Wilson *val = op.value; 205*956a9202SRyan Wilson } else if (err == -ENODEV) { 206*956a9202SRyan Wilson /* No device here, pretend that it just returned 0 */ 207*956a9202SRyan Wilson err = 0; 208*956a9202SRyan Wilson *val = 0; 209*956a9202SRyan Wilson } 210*956a9202SRyan Wilson 211*956a9202SRyan Wilson return errno_to_pcibios_err(err); 212*956a9202SRyan Wilson } 213*956a9202SRyan Wilson 214*956a9202SRyan Wilson /* Access to this function is spinlocked in drivers/pci/access.c */ 215*956a9202SRyan Wilson static int pcifront_bus_write(struct pci_bus *bus, unsigned int devfn, 216*956a9202SRyan Wilson int where, int size, u32 val) 217*956a9202SRyan Wilson { 218*956a9202SRyan Wilson struct xen_pci_op op = { 219*956a9202SRyan Wilson .cmd = XEN_PCI_OP_conf_write, 220*956a9202SRyan Wilson .domain = pci_domain_nr(bus), 221*956a9202SRyan Wilson .bus = bus->number, 222*956a9202SRyan Wilson .devfn = devfn, 223*956a9202SRyan Wilson .offset = where, 224*956a9202SRyan Wilson .size = size, 225*956a9202SRyan Wilson .value = val, 226*956a9202SRyan Wilson }; 227*956a9202SRyan Wilson struct pcifront_sd *sd = bus->sysdata; 228*956a9202SRyan Wilson struct pcifront_device *pdev = pcifront_get_pdev(sd); 229*956a9202SRyan Wilson 230*956a9202SRyan Wilson if (verbose_request) 231*956a9202SRyan Wilson dev_info(&pdev->xdev->dev, 232*956a9202SRyan Wilson "write dev=%04x:%02x:%02x.%01x - " 233*956a9202SRyan Wilson "offset %x size %d val %x\n", 234*956a9202SRyan Wilson pci_domain_nr(bus), bus->number, 235*956a9202SRyan Wilson PCI_SLOT(devfn), PCI_FUNC(devfn), where, size, val); 236*956a9202SRyan Wilson 237*956a9202SRyan Wilson return errno_to_pcibios_err(do_pci_op(pdev, &op)); 238*956a9202SRyan Wilson } 239*956a9202SRyan Wilson 240*956a9202SRyan Wilson struct pci_ops pcifront_bus_ops = { 241*956a9202SRyan Wilson .read = pcifront_bus_read, 242*956a9202SRyan Wilson .write = pcifront_bus_write, 243*956a9202SRyan Wilson }; 244*956a9202SRyan Wilson 245*956a9202SRyan Wilson #ifdef CONFIG_PCI_MSI 246*956a9202SRyan Wilson static int pci_frontend_enable_msix(struct pci_dev *dev, 247*956a9202SRyan Wilson int **vector, int nvec) 248*956a9202SRyan Wilson { 249*956a9202SRyan Wilson int err; 250*956a9202SRyan Wilson int i; 251*956a9202SRyan Wilson struct xen_pci_op op = { 252*956a9202SRyan Wilson .cmd = XEN_PCI_OP_enable_msix, 253*956a9202SRyan Wilson .domain = pci_domain_nr(dev->bus), 254*956a9202SRyan Wilson .bus = dev->bus->number, 255*956a9202SRyan Wilson .devfn = dev->devfn, 256*956a9202SRyan Wilson .value = nvec, 257*956a9202SRyan Wilson }; 258*956a9202SRyan Wilson struct pcifront_sd *sd = dev->bus->sysdata; 259*956a9202SRyan Wilson struct pcifront_device *pdev = pcifront_get_pdev(sd); 260*956a9202SRyan Wilson struct msi_desc *entry; 261*956a9202SRyan Wilson 262*956a9202SRyan Wilson if (nvec > SH_INFO_MAX_VEC) { 263*956a9202SRyan Wilson dev_err(&dev->dev, "too much vector for pci frontend: %x." 264*956a9202SRyan Wilson " Increase SH_INFO_MAX_VEC.\n", nvec); 265*956a9202SRyan Wilson return -EINVAL; 266*956a9202SRyan Wilson } 267*956a9202SRyan Wilson 268*956a9202SRyan Wilson i = 0; 269*956a9202SRyan Wilson list_for_each_entry(entry, &dev->msi_list, list) { 270*956a9202SRyan Wilson op.msix_entries[i].entry = entry->msi_attrib.entry_nr; 271*956a9202SRyan Wilson /* Vector is useless at this point. */ 272*956a9202SRyan Wilson op.msix_entries[i].vector = -1; 273*956a9202SRyan Wilson i++; 274*956a9202SRyan Wilson } 275*956a9202SRyan Wilson 276*956a9202SRyan Wilson err = do_pci_op(pdev, &op); 277*956a9202SRyan Wilson 278*956a9202SRyan Wilson if (likely(!err)) { 279*956a9202SRyan Wilson if (likely(!op.value)) { 280*956a9202SRyan Wilson /* we get the result */ 281*956a9202SRyan Wilson for (i = 0; i < nvec; i++) 282*956a9202SRyan Wilson *(*vector+i) = op.msix_entries[i].vector; 283*956a9202SRyan Wilson return 0; 284*956a9202SRyan Wilson } else { 285*956a9202SRyan Wilson printk(KERN_DEBUG "enable msix get value %x\n", 286*956a9202SRyan Wilson op.value); 287*956a9202SRyan Wilson return op.value; 288*956a9202SRyan Wilson } 289*956a9202SRyan Wilson } else { 290*956a9202SRyan Wilson dev_err(&dev->dev, "enable msix get err %x\n", err); 291*956a9202SRyan Wilson return err; 292*956a9202SRyan Wilson } 293*956a9202SRyan Wilson } 294*956a9202SRyan Wilson 295*956a9202SRyan Wilson static void pci_frontend_disable_msix(struct pci_dev *dev) 296*956a9202SRyan Wilson { 297*956a9202SRyan Wilson int err; 298*956a9202SRyan Wilson struct xen_pci_op op = { 299*956a9202SRyan Wilson .cmd = XEN_PCI_OP_disable_msix, 300*956a9202SRyan Wilson .domain = pci_domain_nr(dev->bus), 301*956a9202SRyan Wilson .bus = dev->bus->number, 302*956a9202SRyan Wilson .devfn = dev->devfn, 303*956a9202SRyan Wilson }; 304*956a9202SRyan Wilson struct pcifront_sd *sd = dev->bus->sysdata; 305*956a9202SRyan Wilson struct pcifront_device *pdev = pcifront_get_pdev(sd); 306*956a9202SRyan Wilson 307*956a9202SRyan Wilson err = do_pci_op(pdev, &op); 308*956a9202SRyan Wilson 309*956a9202SRyan Wilson /* What should do for error ? */ 310*956a9202SRyan Wilson if (err) 311*956a9202SRyan Wilson dev_err(&dev->dev, "pci_disable_msix get err %x\n", err); 312*956a9202SRyan Wilson } 313*956a9202SRyan Wilson 314*956a9202SRyan Wilson static int pci_frontend_enable_msi(struct pci_dev *dev, int **vector) 315*956a9202SRyan Wilson { 316*956a9202SRyan Wilson int err; 317*956a9202SRyan Wilson struct xen_pci_op op = { 318*956a9202SRyan Wilson .cmd = XEN_PCI_OP_enable_msi, 319*956a9202SRyan Wilson .domain = pci_domain_nr(dev->bus), 320*956a9202SRyan Wilson .bus = dev->bus->number, 321*956a9202SRyan Wilson .devfn = dev->devfn, 322*956a9202SRyan Wilson }; 323*956a9202SRyan Wilson struct pcifront_sd *sd = dev->bus->sysdata; 324*956a9202SRyan Wilson struct pcifront_device *pdev = pcifront_get_pdev(sd); 325*956a9202SRyan Wilson 326*956a9202SRyan Wilson err = do_pci_op(pdev, &op); 327*956a9202SRyan Wilson if (likely(!err)) { 328*956a9202SRyan Wilson *(*vector) = op.value; 329*956a9202SRyan Wilson } else { 330*956a9202SRyan Wilson dev_err(&dev->dev, "pci frontend enable msi failed for dev " 331*956a9202SRyan Wilson "%x:%x\n", op.bus, op.devfn); 332*956a9202SRyan Wilson err = -EINVAL; 333*956a9202SRyan Wilson } 334*956a9202SRyan Wilson return err; 335*956a9202SRyan Wilson } 336*956a9202SRyan Wilson 337*956a9202SRyan Wilson static void pci_frontend_disable_msi(struct pci_dev *dev) 338*956a9202SRyan Wilson { 339*956a9202SRyan Wilson int err; 340*956a9202SRyan Wilson struct xen_pci_op op = { 341*956a9202SRyan Wilson .cmd = XEN_PCI_OP_disable_msi, 342*956a9202SRyan Wilson .domain = pci_domain_nr(dev->bus), 343*956a9202SRyan Wilson .bus = dev->bus->number, 344*956a9202SRyan Wilson .devfn = dev->devfn, 345*956a9202SRyan Wilson }; 346*956a9202SRyan Wilson struct pcifront_sd *sd = dev->bus->sysdata; 347*956a9202SRyan Wilson struct pcifront_device *pdev = pcifront_get_pdev(sd); 348*956a9202SRyan Wilson 349*956a9202SRyan Wilson err = do_pci_op(pdev, &op); 350*956a9202SRyan Wilson if (err == XEN_PCI_ERR_dev_not_found) { 351*956a9202SRyan Wilson /* XXX No response from backend, what shall we do? */ 352*956a9202SRyan Wilson printk(KERN_DEBUG "get no response from backend for disable MSI\n"); 353*956a9202SRyan Wilson return; 354*956a9202SRyan Wilson } 355*956a9202SRyan Wilson if (err) 356*956a9202SRyan Wilson /* how can pciback notify us fail? */ 357*956a9202SRyan Wilson printk(KERN_DEBUG "get fake response frombackend\n"); 358*956a9202SRyan Wilson } 359*956a9202SRyan Wilson 360*956a9202SRyan Wilson static struct xen_pci_frontend_ops pci_frontend_ops = { 361*956a9202SRyan Wilson .enable_msi = pci_frontend_enable_msi, 362*956a9202SRyan Wilson .disable_msi = pci_frontend_disable_msi, 363*956a9202SRyan Wilson .enable_msix = pci_frontend_enable_msix, 364*956a9202SRyan Wilson .disable_msix = pci_frontend_disable_msix, 365*956a9202SRyan Wilson }; 366*956a9202SRyan Wilson 367*956a9202SRyan Wilson static void pci_frontend_registrar(int enable) 368*956a9202SRyan Wilson { 369*956a9202SRyan Wilson if (enable) 370*956a9202SRyan Wilson xen_pci_frontend = &pci_frontend_ops; 371*956a9202SRyan Wilson else 372*956a9202SRyan Wilson xen_pci_frontend = NULL; 373*956a9202SRyan Wilson }; 374*956a9202SRyan Wilson #else 375*956a9202SRyan Wilson static inline void pci_frontend_registrar(int enable) { }; 376*956a9202SRyan Wilson #endif /* CONFIG_PCI_MSI */ 377*956a9202SRyan Wilson 378*956a9202SRyan Wilson /* Claim resources for the PCI frontend as-is, backend won't allow changes */ 379*956a9202SRyan Wilson static int pcifront_claim_resource(struct pci_dev *dev, void *data) 380*956a9202SRyan Wilson { 381*956a9202SRyan Wilson struct pcifront_device *pdev = data; 382*956a9202SRyan Wilson int i; 383*956a9202SRyan Wilson struct resource *r; 384*956a9202SRyan Wilson 385*956a9202SRyan Wilson for (i = 0; i < PCI_NUM_RESOURCES; i++) { 386*956a9202SRyan Wilson r = &dev->resource[i]; 387*956a9202SRyan Wilson 388*956a9202SRyan Wilson if (!r->parent && r->start && r->flags) { 389*956a9202SRyan Wilson dev_info(&pdev->xdev->dev, "claiming resource %s/%d\n", 390*956a9202SRyan Wilson pci_name(dev), i); 391*956a9202SRyan Wilson if (pci_claim_resource(dev, i)) { 392*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, "Could not claim " 393*956a9202SRyan Wilson "resource %s/%d! Device offline. Try " 394*956a9202SRyan Wilson "giving less than 4GB to domain.\n", 395*956a9202SRyan Wilson pci_name(dev), i); 396*956a9202SRyan Wilson } 397*956a9202SRyan Wilson } 398*956a9202SRyan Wilson } 399*956a9202SRyan Wilson 400*956a9202SRyan Wilson return 0; 401*956a9202SRyan Wilson } 402*956a9202SRyan Wilson 403*956a9202SRyan Wilson static int __devinit pcifront_scan_bus(struct pcifront_device *pdev, 404*956a9202SRyan Wilson unsigned int domain, unsigned int bus, 405*956a9202SRyan Wilson struct pci_bus *b) 406*956a9202SRyan Wilson { 407*956a9202SRyan Wilson struct pci_dev *d; 408*956a9202SRyan Wilson unsigned int devfn; 409*956a9202SRyan Wilson 410*956a9202SRyan Wilson /* Scan the bus for functions and add. 411*956a9202SRyan Wilson * We omit handling of PCI bridge attachment because pciback prevents 412*956a9202SRyan Wilson * bridges from being exported. 413*956a9202SRyan Wilson */ 414*956a9202SRyan Wilson for (devfn = 0; devfn < 0x100; devfn++) { 415*956a9202SRyan Wilson d = pci_get_slot(b, devfn); 416*956a9202SRyan Wilson if (d) { 417*956a9202SRyan Wilson /* Device is already known. */ 418*956a9202SRyan Wilson pci_dev_put(d); 419*956a9202SRyan Wilson continue; 420*956a9202SRyan Wilson } 421*956a9202SRyan Wilson 422*956a9202SRyan Wilson d = pci_scan_single_device(b, devfn); 423*956a9202SRyan Wilson if (d) 424*956a9202SRyan Wilson dev_info(&pdev->xdev->dev, "New device on " 425*956a9202SRyan Wilson "%04x:%02x:%02x.%02x found.\n", domain, bus, 426*956a9202SRyan Wilson PCI_SLOT(devfn), PCI_FUNC(devfn)); 427*956a9202SRyan Wilson } 428*956a9202SRyan Wilson 429*956a9202SRyan Wilson return 0; 430*956a9202SRyan Wilson } 431*956a9202SRyan Wilson 432*956a9202SRyan Wilson static int __devinit pcifront_scan_root(struct pcifront_device *pdev, 433*956a9202SRyan Wilson unsigned int domain, unsigned int bus) 434*956a9202SRyan Wilson { 435*956a9202SRyan Wilson struct pci_bus *b; 436*956a9202SRyan Wilson struct pcifront_sd *sd = NULL; 437*956a9202SRyan Wilson struct pci_bus_entry *bus_entry = NULL; 438*956a9202SRyan Wilson int err = 0; 439*956a9202SRyan Wilson 440*956a9202SRyan Wilson #ifndef CONFIG_PCI_DOMAINS 441*956a9202SRyan Wilson if (domain != 0) { 442*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, 443*956a9202SRyan Wilson "PCI Root in non-zero PCI Domain! domain=%d\n", domain); 444*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, 445*956a9202SRyan Wilson "Please compile with CONFIG_PCI_DOMAINS\n"); 446*956a9202SRyan Wilson err = -EINVAL; 447*956a9202SRyan Wilson goto err_out; 448*956a9202SRyan Wilson } 449*956a9202SRyan Wilson #endif 450*956a9202SRyan Wilson 451*956a9202SRyan Wilson dev_info(&pdev->xdev->dev, "Creating PCI Frontend Bus %04x:%02x\n", 452*956a9202SRyan Wilson domain, bus); 453*956a9202SRyan Wilson 454*956a9202SRyan Wilson bus_entry = kmalloc(sizeof(*bus_entry), GFP_KERNEL); 455*956a9202SRyan Wilson sd = kmalloc(sizeof(*sd), GFP_KERNEL); 456*956a9202SRyan Wilson if (!bus_entry || !sd) { 457*956a9202SRyan Wilson err = -ENOMEM; 458*956a9202SRyan Wilson goto err_out; 459*956a9202SRyan Wilson } 460*956a9202SRyan Wilson pcifront_init_sd(sd, domain, bus, pdev); 461*956a9202SRyan Wilson 462*956a9202SRyan Wilson b = pci_scan_bus_parented(&pdev->xdev->dev, bus, 463*956a9202SRyan Wilson &pcifront_bus_ops, sd); 464*956a9202SRyan Wilson if (!b) { 465*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, 466*956a9202SRyan Wilson "Error creating PCI Frontend Bus!\n"); 467*956a9202SRyan Wilson err = -ENOMEM; 468*956a9202SRyan Wilson goto err_out; 469*956a9202SRyan Wilson } 470*956a9202SRyan Wilson 471*956a9202SRyan Wilson bus_entry->bus = b; 472*956a9202SRyan Wilson 473*956a9202SRyan Wilson list_add(&bus_entry->list, &pdev->root_buses); 474*956a9202SRyan Wilson 475*956a9202SRyan Wilson /* pci_scan_bus_parented skips devices which do not have a have 476*956a9202SRyan Wilson * devfn==0. The pcifront_scan_bus enumerates all devfn. */ 477*956a9202SRyan Wilson err = pcifront_scan_bus(pdev, domain, bus, b); 478*956a9202SRyan Wilson 479*956a9202SRyan Wilson /* Claim resources before going "live" with our devices */ 480*956a9202SRyan Wilson pci_walk_bus(b, pcifront_claim_resource, pdev); 481*956a9202SRyan Wilson 482*956a9202SRyan Wilson /* Create SysFS and notify udev of the devices. Aka: "going live" */ 483*956a9202SRyan Wilson pci_bus_add_devices(b); 484*956a9202SRyan Wilson 485*956a9202SRyan Wilson return err; 486*956a9202SRyan Wilson 487*956a9202SRyan Wilson err_out: 488*956a9202SRyan Wilson kfree(bus_entry); 489*956a9202SRyan Wilson kfree(sd); 490*956a9202SRyan Wilson 491*956a9202SRyan Wilson return err; 492*956a9202SRyan Wilson } 493*956a9202SRyan Wilson 494*956a9202SRyan Wilson static int __devinit pcifront_rescan_root(struct pcifront_device *pdev, 495*956a9202SRyan Wilson unsigned int domain, unsigned int bus) 496*956a9202SRyan Wilson { 497*956a9202SRyan Wilson int err; 498*956a9202SRyan Wilson struct pci_bus *b; 499*956a9202SRyan Wilson 500*956a9202SRyan Wilson #ifndef CONFIG_PCI_DOMAINS 501*956a9202SRyan Wilson if (domain != 0) { 502*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, 503*956a9202SRyan Wilson "PCI Root in non-zero PCI Domain! domain=%d\n", domain); 504*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, 505*956a9202SRyan Wilson "Please compile with CONFIG_PCI_DOMAINS\n"); 506*956a9202SRyan Wilson return -EINVAL; 507*956a9202SRyan Wilson } 508*956a9202SRyan Wilson #endif 509*956a9202SRyan Wilson 510*956a9202SRyan Wilson dev_info(&pdev->xdev->dev, "Rescanning PCI Frontend Bus %04x:%02x\n", 511*956a9202SRyan Wilson domain, bus); 512*956a9202SRyan Wilson 513*956a9202SRyan Wilson b = pci_find_bus(domain, bus); 514*956a9202SRyan Wilson if (!b) 515*956a9202SRyan Wilson /* If the bus is unknown, create it. */ 516*956a9202SRyan Wilson return pcifront_scan_root(pdev, domain, bus); 517*956a9202SRyan Wilson 518*956a9202SRyan Wilson err = pcifront_scan_bus(pdev, domain, bus, b); 519*956a9202SRyan Wilson 520*956a9202SRyan Wilson /* Claim resources before going "live" with our devices */ 521*956a9202SRyan Wilson pci_walk_bus(b, pcifront_claim_resource, pdev); 522*956a9202SRyan Wilson 523*956a9202SRyan Wilson /* Create SysFS and notify udev of the devices. Aka: "going live" */ 524*956a9202SRyan Wilson pci_bus_add_devices(b); 525*956a9202SRyan Wilson 526*956a9202SRyan Wilson return err; 527*956a9202SRyan Wilson } 528*956a9202SRyan Wilson 529*956a9202SRyan Wilson static void free_root_bus_devs(struct pci_bus *bus) 530*956a9202SRyan Wilson { 531*956a9202SRyan Wilson struct pci_dev *dev; 532*956a9202SRyan Wilson 533*956a9202SRyan Wilson while (!list_empty(&bus->devices)) { 534*956a9202SRyan Wilson dev = container_of(bus->devices.next, struct pci_dev, 535*956a9202SRyan Wilson bus_list); 536*956a9202SRyan Wilson dev_dbg(&dev->dev, "removing device\n"); 537*956a9202SRyan Wilson pci_remove_bus_device(dev); 538*956a9202SRyan Wilson } 539*956a9202SRyan Wilson } 540*956a9202SRyan Wilson 541*956a9202SRyan Wilson static void pcifront_free_roots(struct pcifront_device *pdev) 542*956a9202SRyan Wilson { 543*956a9202SRyan Wilson struct pci_bus_entry *bus_entry, *t; 544*956a9202SRyan Wilson 545*956a9202SRyan Wilson dev_dbg(&pdev->xdev->dev, "cleaning up root buses\n"); 546*956a9202SRyan Wilson 547*956a9202SRyan Wilson list_for_each_entry_safe(bus_entry, t, &pdev->root_buses, list) { 548*956a9202SRyan Wilson list_del(&bus_entry->list); 549*956a9202SRyan Wilson 550*956a9202SRyan Wilson free_root_bus_devs(bus_entry->bus); 551*956a9202SRyan Wilson 552*956a9202SRyan Wilson kfree(bus_entry->bus->sysdata); 553*956a9202SRyan Wilson 554*956a9202SRyan Wilson device_unregister(bus_entry->bus->bridge); 555*956a9202SRyan Wilson pci_remove_bus(bus_entry->bus); 556*956a9202SRyan Wilson 557*956a9202SRyan Wilson kfree(bus_entry); 558*956a9202SRyan Wilson } 559*956a9202SRyan Wilson } 560*956a9202SRyan Wilson 561*956a9202SRyan Wilson static pci_ers_result_t pcifront_common_process(int cmd, 562*956a9202SRyan Wilson struct pcifront_device *pdev, 563*956a9202SRyan Wilson pci_channel_state_t state) 564*956a9202SRyan Wilson { 565*956a9202SRyan Wilson pci_ers_result_t result; 566*956a9202SRyan Wilson struct pci_driver *pdrv; 567*956a9202SRyan Wilson int bus = pdev->sh_info->aer_op.bus; 568*956a9202SRyan Wilson int devfn = pdev->sh_info->aer_op.devfn; 569*956a9202SRyan Wilson struct pci_dev *pcidev; 570*956a9202SRyan Wilson int flag = 0; 571*956a9202SRyan Wilson 572*956a9202SRyan Wilson dev_dbg(&pdev->xdev->dev, 573*956a9202SRyan Wilson "pcifront AER process: cmd %x (bus:%x, devfn%x)", 574*956a9202SRyan Wilson cmd, bus, devfn); 575*956a9202SRyan Wilson result = PCI_ERS_RESULT_NONE; 576*956a9202SRyan Wilson 577*956a9202SRyan Wilson pcidev = pci_get_bus_and_slot(bus, devfn); 578*956a9202SRyan Wilson if (!pcidev || !pcidev->driver) { 579*956a9202SRyan Wilson dev_err(&pcidev->dev, 580*956a9202SRyan Wilson "device or driver is NULL\n"); 581*956a9202SRyan Wilson return result; 582*956a9202SRyan Wilson } 583*956a9202SRyan Wilson pdrv = pcidev->driver; 584*956a9202SRyan Wilson 585*956a9202SRyan Wilson if (get_driver(&pdrv->driver)) { 586*956a9202SRyan Wilson if (pdrv->err_handler && pdrv->err_handler->error_detected) { 587*956a9202SRyan Wilson dev_dbg(&pcidev->dev, 588*956a9202SRyan Wilson "trying to call AER service\n"); 589*956a9202SRyan Wilson if (pcidev) { 590*956a9202SRyan Wilson flag = 1; 591*956a9202SRyan Wilson switch (cmd) { 592*956a9202SRyan Wilson case XEN_PCI_OP_aer_detected: 593*956a9202SRyan Wilson result = pdrv->err_handler-> 594*956a9202SRyan Wilson error_detected(pcidev, state); 595*956a9202SRyan Wilson break; 596*956a9202SRyan Wilson case XEN_PCI_OP_aer_mmio: 597*956a9202SRyan Wilson result = pdrv->err_handler-> 598*956a9202SRyan Wilson mmio_enabled(pcidev); 599*956a9202SRyan Wilson break; 600*956a9202SRyan Wilson case XEN_PCI_OP_aer_slotreset: 601*956a9202SRyan Wilson result = pdrv->err_handler-> 602*956a9202SRyan Wilson slot_reset(pcidev); 603*956a9202SRyan Wilson break; 604*956a9202SRyan Wilson case XEN_PCI_OP_aer_resume: 605*956a9202SRyan Wilson pdrv->err_handler->resume(pcidev); 606*956a9202SRyan Wilson break; 607*956a9202SRyan Wilson default: 608*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, 609*956a9202SRyan Wilson "bad request in aer recovery " 610*956a9202SRyan Wilson "operation!\n"); 611*956a9202SRyan Wilson 612*956a9202SRyan Wilson } 613*956a9202SRyan Wilson } 614*956a9202SRyan Wilson } 615*956a9202SRyan Wilson put_driver(&pdrv->driver); 616*956a9202SRyan Wilson } 617*956a9202SRyan Wilson if (!flag) 618*956a9202SRyan Wilson result = PCI_ERS_RESULT_NONE; 619*956a9202SRyan Wilson 620*956a9202SRyan Wilson return result; 621*956a9202SRyan Wilson } 622*956a9202SRyan Wilson 623*956a9202SRyan Wilson 624*956a9202SRyan Wilson static void pcifront_do_aer(struct work_struct *data) 625*956a9202SRyan Wilson { 626*956a9202SRyan Wilson struct pcifront_device *pdev = 627*956a9202SRyan Wilson container_of(data, struct pcifront_device, op_work); 628*956a9202SRyan Wilson int cmd = pdev->sh_info->aer_op.cmd; 629*956a9202SRyan Wilson pci_channel_state_t state = 630*956a9202SRyan Wilson (pci_channel_state_t)pdev->sh_info->aer_op.err; 631*956a9202SRyan Wilson 632*956a9202SRyan Wilson /*If a pci_conf op is in progress, 633*956a9202SRyan Wilson we have to wait until it is done before service aer op*/ 634*956a9202SRyan Wilson dev_dbg(&pdev->xdev->dev, 635*956a9202SRyan Wilson "pcifront service aer bus %x devfn %x\n", 636*956a9202SRyan Wilson pdev->sh_info->aer_op.bus, pdev->sh_info->aer_op.devfn); 637*956a9202SRyan Wilson 638*956a9202SRyan Wilson pdev->sh_info->aer_op.err = pcifront_common_process(cmd, pdev, state); 639*956a9202SRyan Wilson 640*956a9202SRyan Wilson /* Post the operation to the guest. */ 641*956a9202SRyan Wilson wmb(); 642*956a9202SRyan Wilson clear_bit(_XEN_PCIB_active, (unsigned long *)&pdev->sh_info->flags); 643*956a9202SRyan Wilson notify_remote_via_evtchn(pdev->evtchn); 644*956a9202SRyan Wilson 645*956a9202SRyan Wilson /*in case of we lost an aer request in four lines time_window*/ 646*956a9202SRyan Wilson smp_mb__before_clear_bit(); 647*956a9202SRyan Wilson clear_bit(_PDEVB_op_active, &pdev->flags); 648*956a9202SRyan Wilson smp_mb__after_clear_bit(); 649*956a9202SRyan Wilson 650*956a9202SRyan Wilson schedule_pcifront_aer_op(pdev); 651*956a9202SRyan Wilson 652*956a9202SRyan Wilson } 653*956a9202SRyan Wilson 654*956a9202SRyan Wilson static irqreturn_t pcifront_handler_aer(int irq, void *dev) 655*956a9202SRyan Wilson { 656*956a9202SRyan Wilson struct pcifront_device *pdev = dev; 657*956a9202SRyan Wilson schedule_pcifront_aer_op(pdev); 658*956a9202SRyan Wilson return IRQ_HANDLED; 659*956a9202SRyan Wilson } 660*956a9202SRyan Wilson static int pcifront_connect(struct pcifront_device *pdev) 661*956a9202SRyan Wilson { 662*956a9202SRyan Wilson int err = 0; 663*956a9202SRyan Wilson 664*956a9202SRyan Wilson spin_lock(&pcifront_dev_lock); 665*956a9202SRyan Wilson 666*956a9202SRyan Wilson if (!pcifront_dev) { 667*956a9202SRyan Wilson dev_info(&pdev->xdev->dev, "Installing PCI frontend\n"); 668*956a9202SRyan Wilson pcifront_dev = pdev; 669*956a9202SRyan Wilson } else { 670*956a9202SRyan Wilson dev_err(&pdev->xdev->dev, "PCI frontend already installed!\n"); 671*956a9202SRyan Wilson err = -EEXIST; 672*956a9202SRyan Wilson } 673*956a9202SRyan Wilson 674*956a9202SRyan Wilson spin_unlock(&pcifront_dev_lock); 675*956a9202SRyan Wilson 676*956a9202SRyan Wilson return err; 677*956a9202SRyan Wilson } 678*956a9202SRyan Wilson 679*956a9202SRyan Wilson static void pcifront_disconnect(struct pcifront_device *pdev) 680*956a9202SRyan Wilson { 681*956a9202SRyan Wilson spin_lock(&pcifront_dev_lock); 682*956a9202SRyan Wilson 683*956a9202SRyan Wilson if (pdev == pcifront_dev) { 684*956a9202SRyan Wilson dev_info(&pdev->xdev->dev, 685*956a9202SRyan Wilson "Disconnecting PCI Frontend Buses\n"); 686*956a9202SRyan Wilson pcifront_dev = NULL; 687*956a9202SRyan Wilson } 688*956a9202SRyan Wilson 689*956a9202SRyan Wilson spin_unlock(&pcifront_dev_lock); 690*956a9202SRyan Wilson } 691*956a9202SRyan Wilson static struct pcifront_device *alloc_pdev(struct xenbus_device *xdev) 692*956a9202SRyan Wilson { 693*956a9202SRyan Wilson struct pcifront_device *pdev; 694*956a9202SRyan Wilson 695*956a9202SRyan Wilson pdev = kzalloc(sizeof(struct pcifront_device), GFP_KERNEL); 696*956a9202SRyan Wilson if (pdev == NULL) 697*956a9202SRyan Wilson goto out; 698*956a9202SRyan Wilson 699*956a9202SRyan Wilson pdev->sh_info = 700*956a9202SRyan Wilson (struct xen_pci_sharedinfo *)__get_free_page(GFP_KERNEL); 701*956a9202SRyan Wilson if (pdev->sh_info == NULL) { 702*956a9202SRyan Wilson kfree(pdev); 703*956a9202SRyan Wilson pdev = NULL; 704*956a9202SRyan Wilson goto out; 705*956a9202SRyan Wilson } 706*956a9202SRyan Wilson pdev->sh_info->flags = 0; 707*956a9202SRyan Wilson 708*956a9202SRyan Wilson /*Flag for registering PV AER handler*/ 709*956a9202SRyan Wilson set_bit(_XEN_PCIB_AERHANDLER, (void *)&pdev->sh_info->flags); 710*956a9202SRyan Wilson 711*956a9202SRyan Wilson dev_set_drvdata(&xdev->dev, pdev); 712*956a9202SRyan Wilson pdev->xdev = xdev; 713*956a9202SRyan Wilson 714*956a9202SRyan Wilson INIT_LIST_HEAD(&pdev->root_buses); 715*956a9202SRyan Wilson 716*956a9202SRyan Wilson spin_lock_init(&pdev->sh_info_lock); 717*956a9202SRyan Wilson 718*956a9202SRyan Wilson pdev->evtchn = INVALID_EVTCHN; 719*956a9202SRyan Wilson pdev->gnt_ref = INVALID_GRANT_REF; 720*956a9202SRyan Wilson pdev->irq = -1; 721*956a9202SRyan Wilson 722*956a9202SRyan Wilson INIT_WORK(&pdev->op_work, pcifront_do_aer); 723*956a9202SRyan Wilson 724*956a9202SRyan Wilson dev_dbg(&xdev->dev, "Allocated pdev @ 0x%p pdev->sh_info @ 0x%p\n", 725*956a9202SRyan Wilson pdev, pdev->sh_info); 726*956a9202SRyan Wilson out: 727*956a9202SRyan Wilson return pdev; 728*956a9202SRyan Wilson } 729*956a9202SRyan Wilson 730*956a9202SRyan Wilson static void free_pdev(struct pcifront_device *pdev) 731*956a9202SRyan Wilson { 732*956a9202SRyan Wilson dev_dbg(&pdev->xdev->dev, "freeing pdev @ 0x%p\n", pdev); 733*956a9202SRyan Wilson 734*956a9202SRyan Wilson pcifront_free_roots(pdev); 735*956a9202SRyan Wilson 736*956a9202SRyan Wilson /*For PCIE_AER error handling job*/ 737*956a9202SRyan Wilson flush_scheduled_work(); 738*956a9202SRyan Wilson 739*956a9202SRyan Wilson if (pdev->irq >= 0) 740*956a9202SRyan Wilson unbind_from_irqhandler(pdev->irq, pdev); 741*956a9202SRyan Wilson 742*956a9202SRyan Wilson if (pdev->evtchn != INVALID_EVTCHN) 743*956a9202SRyan Wilson xenbus_free_evtchn(pdev->xdev, pdev->evtchn); 744*956a9202SRyan Wilson 745*956a9202SRyan Wilson if (pdev->gnt_ref != INVALID_GRANT_REF) 746*956a9202SRyan Wilson gnttab_end_foreign_access(pdev->gnt_ref, 0 /* r/w page */, 747*956a9202SRyan Wilson (unsigned long)pdev->sh_info); 748*956a9202SRyan Wilson else 749*956a9202SRyan Wilson free_page((unsigned long)pdev->sh_info); 750*956a9202SRyan Wilson 751*956a9202SRyan Wilson dev_set_drvdata(&pdev->xdev->dev, NULL); 752*956a9202SRyan Wilson 753*956a9202SRyan Wilson kfree(pdev); 754*956a9202SRyan Wilson } 755*956a9202SRyan Wilson 756*956a9202SRyan Wilson static int pcifront_publish_info(struct pcifront_device *pdev) 757*956a9202SRyan Wilson { 758*956a9202SRyan Wilson int err = 0; 759*956a9202SRyan Wilson struct xenbus_transaction trans; 760*956a9202SRyan Wilson 761*956a9202SRyan Wilson err = xenbus_grant_ring(pdev->xdev, virt_to_mfn(pdev->sh_info)); 762*956a9202SRyan Wilson if (err < 0) 763*956a9202SRyan Wilson goto out; 764*956a9202SRyan Wilson 765*956a9202SRyan Wilson pdev->gnt_ref = err; 766*956a9202SRyan Wilson 767*956a9202SRyan Wilson err = xenbus_alloc_evtchn(pdev->xdev, &pdev->evtchn); 768*956a9202SRyan Wilson if (err) 769*956a9202SRyan Wilson goto out; 770*956a9202SRyan Wilson 771*956a9202SRyan Wilson err = bind_evtchn_to_irqhandler(pdev->evtchn, pcifront_handler_aer, 772*956a9202SRyan Wilson 0, "pcifront", pdev); 773*956a9202SRyan Wilson 774*956a9202SRyan Wilson if (err < 0) 775*956a9202SRyan Wilson return err; 776*956a9202SRyan Wilson 777*956a9202SRyan Wilson pdev->irq = err; 778*956a9202SRyan Wilson 779*956a9202SRyan Wilson do_publish: 780*956a9202SRyan Wilson err = xenbus_transaction_start(&trans); 781*956a9202SRyan Wilson if (err) { 782*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 783*956a9202SRyan Wilson "Error writing configuration for backend " 784*956a9202SRyan Wilson "(start transaction)"); 785*956a9202SRyan Wilson goto out; 786*956a9202SRyan Wilson } 787*956a9202SRyan Wilson 788*956a9202SRyan Wilson err = xenbus_printf(trans, pdev->xdev->nodename, 789*956a9202SRyan Wilson "pci-op-ref", "%u", pdev->gnt_ref); 790*956a9202SRyan Wilson if (!err) 791*956a9202SRyan Wilson err = xenbus_printf(trans, pdev->xdev->nodename, 792*956a9202SRyan Wilson "event-channel", "%u", pdev->evtchn); 793*956a9202SRyan Wilson if (!err) 794*956a9202SRyan Wilson err = xenbus_printf(trans, pdev->xdev->nodename, 795*956a9202SRyan Wilson "magic", XEN_PCI_MAGIC); 796*956a9202SRyan Wilson 797*956a9202SRyan Wilson if (err) { 798*956a9202SRyan Wilson xenbus_transaction_end(trans, 1); 799*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 800*956a9202SRyan Wilson "Error writing configuration for backend"); 801*956a9202SRyan Wilson goto out; 802*956a9202SRyan Wilson } else { 803*956a9202SRyan Wilson err = xenbus_transaction_end(trans, 0); 804*956a9202SRyan Wilson if (err == -EAGAIN) 805*956a9202SRyan Wilson goto do_publish; 806*956a9202SRyan Wilson else if (err) { 807*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 808*956a9202SRyan Wilson "Error completing transaction " 809*956a9202SRyan Wilson "for backend"); 810*956a9202SRyan Wilson goto out; 811*956a9202SRyan Wilson } 812*956a9202SRyan Wilson } 813*956a9202SRyan Wilson 814*956a9202SRyan Wilson xenbus_switch_state(pdev->xdev, XenbusStateInitialised); 815*956a9202SRyan Wilson 816*956a9202SRyan Wilson dev_dbg(&pdev->xdev->dev, "publishing successful!\n"); 817*956a9202SRyan Wilson 818*956a9202SRyan Wilson out: 819*956a9202SRyan Wilson return err; 820*956a9202SRyan Wilson } 821*956a9202SRyan Wilson 822*956a9202SRyan Wilson static int __devinit pcifront_try_connect(struct pcifront_device *pdev) 823*956a9202SRyan Wilson { 824*956a9202SRyan Wilson int err = -EFAULT; 825*956a9202SRyan Wilson int i, num_roots, len; 826*956a9202SRyan Wilson char str[64]; 827*956a9202SRyan Wilson unsigned int domain, bus; 828*956a9202SRyan Wilson 829*956a9202SRyan Wilson 830*956a9202SRyan Wilson /* Only connect once */ 831*956a9202SRyan Wilson if (xenbus_read_driver_state(pdev->xdev->nodename) != 832*956a9202SRyan Wilson XenbusStateInitialised) 833*956a9202SRyan Wilson goto out; 834*956a9202SRyan Wilson 835*956a9202SRyan Wilson err = pcifront_connect(pdev); 836*956a9202SRyan Wilson if (err) { 837*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 838*956a9202SRyan Wilson "Error connecting PCI Frontend"); 839*956a9202SRyan Wilson goto out; 840*956a9202SRyan Wilson } 841*956a9202SRyan Wilson 842*956a9202SRyan Wilson err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, 843*956a9202SRyan Wilson "root_num", "%d", &num_roots); 844*956a9202SRyan Wilson if (err == -ENOENT) { 845*956a9202SRyan Wilson xenbus_dev_error(pdev->xdev, err, 846*956a9202SRyan Wilson "No PCI Roots found, trying 0000:00"); 847*956a9202SRyan Wilson err = pcifront_scan_root(pdev, 0, 0); 848*956a9202SRyan Wilson num_roots = 0; 849*956a9202SRyan Wilson } else if (err != 1) { 850*956a9202SRyan Wilson if (err == 0) 851*956a9202SRyan Wilson err = -EINVAL; 852*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 853*956a9202SRyan Wilson "Error reading number of PCI roots"); 854*956a9202SRyan Wilson goto out; 855*956a9202SRyan Wilson } 856*956a9202SRyan Wilson 857*956a9202SRyan Wilson for (i = 0; i < num_roots; i++) { 858*956a9202SRyan Wilson len = snprintf(str, sizeof(str), "root-%d", i); 859*956a9202SRyan Wilson if (unlikely(len >= (sizeof(str) - 1))) { 860*956a9202SRyan Wilson err = -ENOMEM; 861*956a9202SRyan Wilson goto out; 862*956a9202SRyan Wilson } 863*956a9202SRyan Wilson 864*956a9202SRyan Wilson err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, 865*956a9202SRyan Wilson "%x:%x", &domain, &bus); 866*956a9202SRyan Wilson if (err != 2) { 867*956a9202SRyan Wilson if (err >= 0) 868*956a9202SRyan Wilson err = -EINVAL; 869*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 870*956a9202SRyan Wilson "Error reading PCI root %d", i); 871*956a9202SRyan Wilson goto out; 872*956a9202SRyan Wilson } 873*956a9202SRyan Wilson 874*956a9202SRyan Wilson err = pcifront_scan_root(pdev, domain, bus); 875*956a9202SRyan Wilson if (err) { 876*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 877*956a9202SRyan Wilson "Error scanning PCI root %04x:%02x", 878*956a9202SRyan Wilson domain, bus); 879*956a9202SRyan Wilson goto out; 880*956a9202SRyan Wilson } 881*956a9202SRyan Wilson } 882*956a9202SRyan Wilson 883*956a9202SRyan Wilson err = xenbus_switch_state(pdev->xdev, XenbusStateConnected); 884*956a9202SRyan Wilson 885*956a9202SRyan Wilson out: 886*956a9202SRyan Wilson return err; 887*956a9202SRyan Wilson } 888*956a9202SRyan Wilson 889*956a9202SRyan Wilson static int pcifront_try_disconnect(struct pcifront_device *pdev) 890*956a9202SRyan Wilson { 891*956a9202SRyan Wilson int err = 0; 892*956a9202SRyan Wilson enum xenbus_state prev_state; 893*956a9202SRyan Wilson 894*956a9202SRyan Wilson 895*956a9202SRyan Wilson prev_state = xenbus_read_driver_state(pdev->xdev->nodename); 896*956a9202SRyan Wilson 897*956a9202SRyan Wilson if (prev_state >= XenbusStateClosing) 898*956a9202SRyan Wilson goto out; 899*956a9202SRyan Wilson 900*956a9202SRyan Wilson if (prev_state == XenbusStateConnected) { 901*956a9202SRyan Wilson pcifront_free_roots(pdev); 902*956a9202SRyan Wilson pcifront_disconnect(pdev); 903*956a9202SRyan Wilson } 904*956a9202SRyan Wilson 905*956a9202SRyan Wilson err = xenbus_switch_state(pdev->xdev, XenbusStateClosed); 906*956a9202SRyan Wilson 907*956a9202SRyan Wilson out: 908*956a9202SRyan Wilson 909*956a9202SRyan Wilson return err; 910*956a9202SRyan Wilson } 911*956a9202SRyan Wilson 912*956a9202SRyan Wilson static int __devinit pcifront_attach_devices(struct pcifront_device *pdev) 913*956a9202SRyan Wilson { 914*956a9202SRyan Wilson int err = -EFAULT; 915*956a9202SRyan Wilson int i, num_roots, len; 916*956a9202SRyan Wilson unsigned int domain, bus; 917*956a9202SRyan Wilson char str[64]; 918*956a9202SRyan Wilson 919*956a9202SRyan Wilson if (xenbus_read_driver_state(pdev->xdev->nodename) != 920*956a9202SRyan Wilson XenbusStateReconfiguring) 921*956a9202SRyan Wilson goto out; 922*956a9202SRyan Wilson 923*956a9202SRyan Wilson err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, 924*956a9202SRyan Wilson "root_num", "%d", &num_roots); 925*956a9202SRyan Wilson if (err == -ENOENT) { 926*956a9202SRyan Wilson xenbus_dev_error(pdev->xdev, err, 927*956a9202SRyan Wilson "No PCI Roots found, trying 0000:00"); 928*956a9202SRyan Wilson err = pcifront_rescan_root(pdev, 0, 0); 929*956a9202SRyan Wilson num_roots = 0; 930*956a9202SRyan Wilson } else if (err != 1) { 931*956a9202SRyan Wilson if (err == 0) 932*956a9202SRyan Wilson err = -EINVAL; 933*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 934*956a9202SRyan Wilson "Error reading number of PCI roots"); 935*956a9202SRyan Wilson goto out; 936*956a9202SRyan Wilson } 937*956a9202SRyan Wilson 938*956a9202SRyan Wilson for (i = 0; i < num_roots; i++) { 939*956a9202SRyan Wilson len = snprintf(str, sizeof(str), "root-%d", i); 940*956a9202SRyan Wilson if (unlikely(len >= (sizeof(str) - 1))) { 941*956a9202SRyan Wilson err = -ENOMEM; 942*956a9202SRyan Wilson goto out; 943*956a9202SRyan Wilson } 944*956a9202SRyan Wilson 945*956a9202SRyan Wilson err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, 946*956a9202SRyan Wilson "%x:%x", &domain, &bus); 947*956a9202SRyan Wilson if (err != 2) { 948*956a9202SRyan Wilson if (err >= 0) 949*956a9202SRyan Wilson err = -EINVAL; 950*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 951*956a9202SRyan Wilson "Error reading PCI root %d", i); 952*956a9202SRyan Wilson goto out; 953*956a9202SRyan Wilson } 954*956a9202SRyan Wilson 955*956a9202SRyan Wilson err = pcifront_rescan_root(pdev, domain, bus); 956*956a9202SRyan Wilson if (err) { 957*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 958*956a9202SRyan Wilson "Error scanning PCI root %04x:%02x", 959*956a9202SRyan Wilson domain, bus); 960*956a9202SRyan Wilson goto out; 961*956a9202SRyan Wilson } 962*956a9202SRyan Wilson } 963*956a9202SRyan Wilson 964*956a9202SRyan Wilson xenbus_switch_state(pdev->xdev, XenbusStateConnected); 965*956a9202SRyan Wilson 966*956a9202SRyan Wilson out: 967*956a9202SRyan Wilson return err; 968*956a9202SRyan Wilson } 969*956a9202SRyan Wilson 970*956a9202SRyan Wilson static int pcifront_detach_devices(struct pcifront_device *pdev) 971*956a9202SRyan Wilson { 972*956a9202SRyan Wilson int err = 0; 973*956a9202SRyan Wilson int i, num_devs; 974*956a9202SRyan Wilson unsigned int domain, bus, slot, func; 975*956a9202SRyan Wilson struct pci_bus *pci_bus; 976*956a9202SRyan Wilson struct pci_dev *pci_dev; 977*956a9202SRyan Wilson char str[64]; 978*956a9202SRyan Wilson 979*956a9202SRyan Wilson if (xenbus_read_driver_state(pdev->xdev->nodename) != 980*956a9202SRyan Wilson XenbusStateConnected) 981*956a9202SRyan Wilson goto out; 982*956a9202SRyan Wilson 983*956a9202SRyan Wilson err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, "num_devs", "%d", 984*956a9202SRyan Wilson &num_devs); 985*956a9202SRyan Wilson if (err != 1) { 986*956a9202SRyan Wilson if (err >= 0) 987*956a9202SRyan Wilson err = -EINVAL; 988*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 989*956a9202SRyan Wilson "Error reading number of PCI devices"); 990*956a9202SRyan Wilson goto out; 991*956a9202SRyan Wilson } 992*956a9202SRyan Wilson 993*956a9202SRyan Wilson /* Find devices being detached and remove them. */ 994*956a9202SRyan Wilson for (i = 0; i < num_devs; i++) { 995*956a9202SRyan Wilson int l, state; 996*956a9202SRyan Wilson l = snprintf(str, sizeof(str), "state-%d", i); 997*956a9202SRyan Wilson if (unlikely(l >= (sizeof(str) - 1))) { 998*956a9202SRyan Wilson err = -ENOMEM; 999*956a9202SRyan Wilson goto out; 1000*956a9202SRyan Wilson } 1001*956a9202SRyan Wilson err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, "%d", 1002*956a9202SRyan Wilson &state); 1003*956a9202SRyan Wilson if (err != 1) 1004*956a9202SRyan Wilson state = XenbusStateUnknown; 1005*956a9202SRyan Wilson 1006*956a9202SRyan Wilson if (state != XenbusStateClosing) 1007*956a9202SRyan Wilson continue; 1008*956a9202SRyan Wilson 1009*956a9202SRyan Wilson /* Remove device. */ 1010*956a9202SRyan Wilson l = snprintf(str, sizeof(str), "vdev-%d", i); 1011*956a9202SRyan Wilson if (unlikely(l >= (sizeof(str) - 1))) { 1012*956a9202SRyan Wilson err = -ENOMEM; 1013*956a9202SRyan Wilson goto out; 1014*956a9202SRyan Wilson } 1015*956a9202SRyan Wilson err = xenbus_scanf(XBT_NIL, pdev->xdev->otherend, str, 1016*956a9202SRyan Wilson "%x:%x:%x.%x", &domain, &bus, &slot, &func); 1017*956a9202SRyan Wilson if (err != 4) { 1018*956a9202SRyan Wilson if (err >= 0) 1019*956a9202SRyan Wilson err = -EINVAL; 1020*956a9202SRyan Wilson xenbus_dev_fatal(pdev->xdev, err, 1021*956a9202SRyan Wilson "Error reading PCI device %d", i); 1022*956a9202SRyan Wilson goto out; 1023*956a9202SRyan Wilson } 1024*956a9202SRyan Wilson 1025*956a9202SRyan Wilson pci_bus = pci_find_bus(domain, bus); 1026*956a9202SRyan Wilson if (!pci_bus) { 1027*956a9202SRyan Wilson dev_dbg(&pdev->xdev->dev, "Cannot get bus %04x:%02x\n", 1028*956a9202SRyan Wilson domain, bus); 1029*956a9202SRyan Wilson continue; 1030*956a9202SRyan Wilson } 1031*956a9202SRyan Wilson pci_dev = pci_get_slot(pci_bus, PCI_DEVFN(slot, func)); 1032*956a9202SRyan Wilson if (!pci_dev) { 1033*956a9202SRyan Wilson dev_dbg(&pdev->xdev->dev, 1034*956a9202SRyan Wilson "Cannot get PCI device %04x:%02x:%02x.%02x\n", 1035*956a9202SRyan Wilson domain, bus, slot, func); 1036*956a9202SRyan Wilson continue; 1037*956a9202SRyan Wilson } 1038*956a9202SRyan Wilson pci_remove_bus_device(pci_dev); 1039*956a9202SRyan Wilson pci_dev_put(pci_dev); 1040*956a9202SRyan Wilson 1041*956a9202SRyan Wilson dev_dbg(&pdev->xdev->dev, 1042*956a9202SRyan Wilson "PCI device %04x:%02x:%02x.%02x removed.\n", 1043*956a9202SRyan Wilson domain, bus, slot, func); 1044*956a9202SRyan Wilson } 1045*956a9202SRyan Wilson 1046*956a9202SRyan Wilson err = xenbus_switch_state(pdev->xdev, XenbusStateReconfiguring); 1047*956a9202SRyan Wilson 1048*956a9202SRyan Wilson out: 1049*956a9202SRyan Wilson return err; 1050*956a9202SRyan Wilson } 1051*956a9202SRyan Wilson 1052*956a9202SRyan Wilson static void __init_refok pcifront_backend_changed(struct xenbus_device *xdev, 1053*956a9202SRyan Wilson enum xenbus_state be_state) 1054*956a9202SRyan Wilson { 1055*956a9202SRyan Wilson struct pcifront_device *pdev = dev_get_drvdata(&xdev->dev); 1056*956a9202SRyan Wilson 1057*956a9202SRyan Wilson switch (be_state) { 1058*956a9202SRyan Wilson case XenbusStateUnknown: 1059*956a9202SRyan Wilson case XenbusStateInitialising: 1060*956a9202SRyan Wilson case XenbusStateInitWait: 1061*956a9202SRyan Wilson case XenbusStateInitialised: 1062*956a9202SRyan Wilson case XenbusStateClosed: 1063*956a9202SRyan Wilson break; 1064*956a9202SRyan Wilson 1065*956a9202SRyan Wilson case XenbusStateConnected: 1066*956a9202SRyan Wilson pcifront_try_connect(pdev); 1067*956a9202SRyan Wilson break; 1068*956a9202SRyan Wilson 1069*956a9202SRyan Wilson case XenbusStateClosing: 1070*956a9202SRyan Wilson dev_warn(&xdev->dev, "backend going away!\n"); 1071*956a9202SRyan Wilson pcifront_try_disconnect(pdev); 1072*956a9202SRyan Wilson break; 1073*956a9202SRyan Wilson 1074*956a9202SRyan Wilson case XenbusStateReconfiguring: 1075*956a9202SRyan Wilson pcifront_detach_devices(pdev); 1076*956a9202SRyan Wilson break; 1077*956a9202SRyan Wilson 1078*956a9202SRyan Wilson case XenbusStateReconfigured: 1079*956a9202SRyan Wilson pcifront_attach_devices(pdev); 1080*956a9202SRyan Wilson break; 1081*956a9202SRyan Wilson } 1082*956a9202SRyan Wilson } 1083*956a9202SRyan Wilson 1084*956a9202SRyan Wilson static int pcifront_xenbus_probe(struct xenbus_device *xdev, 1085*956a9202SRyan Wilson const struct xenbus_device_id *id) 1086*956a9202SRyan Wilson { 1087*956a9202SRyan Wilson int err = 0; 1088*956a9202SRyan Wilson struct pcifront_device *pdev = alloc_pdev(xdev); 1089*956a9202SRyan Wilson 1090*956a9202SRyan Wilson if (pdev == NULL) { 1091*956a9202SRyan Wilson err = -ENOMEM; 1092*956a9202SRyan Wilson xenbus_dev_fatal(xdev, err, 1093*956a9202SRyan Wilson "Error allocating pcifront_device struct"); 1094*956a9202SRyan Wilson goto out; 1095*956a9202SRyan Wilson } 1096*956a9202SRyan Wilson 1097*956a9202SRyan Wilson err = pcifront_publish_info(pdev); 1098*956a9202SRyan Wilson if (err) 1099*956a9202SRyan Wilson free_pdev(pdev); 1100*956a9202SRyan Wilson 1101*956a9202SRyan Wilson out: 1102*956a9202SRyan Wilson return err; 1103*956a9202SRyan Wilson } 1104*956a9202SRyan Wilson 1105*956a9202SRyan Wilson static int pcifront_xenbus_remove(struct xenbus_device *xdev) 1106*956a9202SRyan Wilson { 1107*956a9202SRyan Wilson struct pcifront_device *pdev = dev_get_drvdata(&xdev->dev); 1108*956a9202SRyan Wilson if (pdev) 1109*956a9202SRyan Wilson free_pdev(pdev); 1110*956a9202SRyan Wilson 1111*956a9202SRyan Wilson return 0; 1112*956a9202SRyan Wilson } 1113*956a9202SRyan Wilson 1114*956a9202SRyan Wilson static const struct xenbus_device_id xenpci_ids[] = { 1115*956a9202SRyan Wilson {"pci"}, 1116*956a9202SRyan Wilson {""}, 1117*956a9202SRyan Wilson }; 1118*956a9202SRyan Wilson 1119*956a9202SRyan Wilson static struct xenbus_driver xenbus_pcifront_driver = { 1120*956a9202SRyan Wilson .name = "pcifront", 1121*956a9202SRyan Wilson .owner = THIS_MODULE, 1122*956a9202SRyan Wilson .ids = xenpci_ids, 1123*956a9202SRyan Wilson .probe = pcifront_xenbus_probe, 1124*956a9202SRyan Wilson .remove = pcifront_xenbus_remove, 1125*956a9202SRyan Wilson .otherend_changed = pcifront_backend_changed, 1126*956a9202SRyan Wilson }; 1127*956a9202SRyan Wilson 1128*956a9202SRyan Wilson static int __init pcifront_init(void) 1129*956a9202SRyan Wilson { 1130*956a9202SRyan Wilson if (!xen_pv_domain() || xen_initial_domain()) 1131*956a9202SRyan Wilson return -ENODEV; 1132*956a9202SRyan Wilson 1133*956a9202SRyan Wilson pci_frontend_registrar(1 /* enable */); 1134*956a9202SRyan Wilson 1135*956a9202SRyan Wilson return xenbus_register_frontend(&xenbus_pcifront_driver); 1136*956a9202SRyan Wilson } 1137*956a9202SRyan Wilson 1138*956a9202SRyan Wilson static void __exit pcifront_cleanup(void) 1139*956a9202SRyan Wilson { 1140*956a9202SRyan Wilson xenbus_unregister_driver(&xenbus_pcifront_driver); 1141*956a9202SRyan Wilson pci_frontend_registrar(0 /* disable */); 1142*956a9202SRyan Wilson } 1143*956a9202SRyan Wilson module_init(pcifront_init); 1144*956a9202SRyan Wilson module_exit(pcifront_cleanup); 1145*956a9202SRyan Wilson 1146*956a9202SRyan Wilson MODULE_DESCRIPTION("Xen PCI passthrough frontend."); 1147*956a9202SRyan Wilson MODULE_LICENSE("GPL"); 1148*956a9202SRyan Wilson MODULE_ALIAS("xen:pci"); 1149