Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen-pcifront: Xen PCI frontend driver.

This is a port of the 2.6.18 Xen PCI front driver with fixes
to make it build under 2.6.34 and later (for the full list of
changes: git://git.kernel.org/pub/scm/linux/kernel/git/konrad/xen.git
historic/xen-pcifront-0.1). It also includes the fixes
to make it work properly.

[v2: Updated Kconfig, removed crud, added Reviewed-by]
[v3: Added 'static', fixed grant table leak, redid Kconfig]
[v4: Added one more 'static' and removed comments]

Signed-off-by: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>
Reviewed-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
Reviewed-by: Jan Beulich <JBeulich@novell.com>

authored by

Ryan Wilson and committed by
Konrad Rzeszutek Wilk
956a9202 b78c9512

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