diff options
Diffstat (limited to 'arch/x86/pci/xen.c')
-rw-r--r-- | arch/x86/pci/xen.c | 96 |
1 files changed, 91 insertions, 5 deletions
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index e37b407a0ee8..8214724ce54d 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c | |||
@@ -108,7 +108,8 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
108 | } | 108 | } |
109 | irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0, | 109 | irq = xen_bind_pirq_msi_to_irq(dev, msidesc, pirq, 0, |
110 | (type == PCI_CAP_ID_MSIX) ? | 110 | (type == PCI_CAP_ID_MSIX) ? |
111 | "msi-x" : "msi"); | 111 | "msi-x" : "msi", |
112 | DOMID_SELF); | ||
112 | if (irq < 0) | 113 | if (irq < 0) |
113 | goto error; | 114 | goto error; |
114 | dev_dbg(&dev->dev, | 115 | dev_dbg(&dev->dev, |
@@ -148,7 +149,8 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
148 | irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0, | 149 | irq = xen_bind_pirq_msi_to_irq(dev, msidesc, v[i], 0, |
149 | (type == PCI_CAP_ID_MSIX) ? | 150 | (type == PCI_CAP_ID_MSIX) ? |
150 | "pcifront-msi-x" : | 151 | "pcifront-msi-x" : |
151 | "pcifront-msi"); | 152 | "pcifront-msi", |
153 | DOMID_SELF); | ||
152 | if (irq < 0) | 154 | if (irq < 0) |
153 | goto free; | 155 | goto free; |
154 | i++; | 156 | i++; |
@@ -190,9 +192,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
190 | 192 | ||
191 | list_for_each_entry(msidesc, &dev->msi_list, list) { | 193 | list_for_each_entry(msidesc, &dev->msi_list, list) { |
192 | struct physdev_map_pirq map_irq; | 194 | struct physdev_map_pirq map_irq; |
195 | domid_t domid; | ||
196 | |||
197 | domid = ret = xen_find_device_domain_owner(dev); | ||
198 | /* N.B. Casting int's -ENODEV to uint16_t results in 0xFFED, | ||
199 | * hence check ret value for < 0. */ | ||
200 | if (ret < 0) | ||
201 | domid = DOMID_SELF; | ||
193 | 202 | ||
194 | memset(&map_irq, 0, sizeof(map_irq)); | 203 | memset(&map_irq, 0, sizeof(map_irq)); |
195 | map_irq.domid = DOMID_SELF; | 204 | map_irq.domid = domid; |
196 | map_irq.type = MAP_PIRQ_TYPE_MSI; | 205 | map_irq.type = MAP_PIRQ_TYPE_MSI; |
197 | map_irq.index = -1; | 206 | map_irq.index = -1; |
198 | map_irq.pirq = -1; | 207 | map_irq.pirq = -1; |
@@ -215,14 +224,16 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) | |||
215 | 224 | ||
216 | ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); | 225 | ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq); |
217 | if (ret) { | 226 | if (ret) { |
218 | dev_warn(&dev->dev, "xen map irq failed %d\n", ret); | 227 | dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n", |
228 | ret, domid); | ||
219 | goto out; | 229 | goto out; |
220 | } | 230 | } |
221 | 231 | ||
222 | ret = xen_bind_pirq_msi_to_irq(dev, msidesc, | 232 | ret = xen_bind_pirq_msi_to_irq(dev, msidesc, |
223 | map_irq.pirq, map_irq.index, | 233 | map_irq.pirq, map_irq.index, |
224 | (type == PCI_CAP_ID_MSIX) ? | 234 | (type == PCI_CAP_ID_MSIX) ? |
225 | "msi-x" : "msi"); | 235 | "msi-x" : "msi", |
236 | domid); | ||
226 | if (ret < 0) | 237 | if (ret < 0) |
227 | goto out; | 238 | goto out; |
228 | } | 239 | } |
@@ -461,3 +472,78 @@ void __init xen_setup_pirqs(void) | |||
461 | } | 472 | } |
462 | } | 473 | } |
463 | #endif | 474 | #endif |
475 | |||
476 | #ifdef CONFIG_XEN_DOM0 | ||
477 | struct xen_device_domain_owner { | ||
478 | domid_t domain; | ||
479 | struct pci_dev *dev; | ||
480 | struct list_head list; | ||
481 | }; | ||
482 | |||
483 | static DEFINE_SPINLOCK(dev_domain_list_spinlock); | ||
484 | static struct list_head dev_domain_list = LIST_HEAD_INIT(dev_domain_list); | ||
485 | |||
486 | static struct xen_device_domain_owner *find_device(struct pci_dev *dev) | ||
487 | { | ||
488 | struct xen_device_domain_owner *owner; | ||
489 | |||
490 | list_for_each_entry(owner, &dev_domain_list, list) { | ||
491 | if (owner->dev == dev) | ||
492 | return owner; | ||
493 | } | ||
494 | return NULL; | ||
495 | } | ||
496 | |||
497 | int xen_find_device_domain_owner(struct pci_dev *dev) | ||
498 | { | ||
499 | struct xen_device_domain_owner *owner; | ||
500 | int domain = -ENODEV; | ||
501 | |||
502 | spin_lock(&dev_domain_list_spinlock); | ||
503 | owner = find_device(dev); | ||
504 | if (owner) | ||
505 | domain = owner->domain; | ||
506 | spin_unlock(&dev_domain_list_spinlock); | ||
507 | return domain; | ||
508 | } | ||
509 | EXPORT_SYMBOL_GPL(xen_find_device_domain_owner); | ||
510 | |||
511 | int xen_register_device_domain_owner(struct pci_dev *dev, uint16_t domain) | ||
512 | { | ||
513 | struct xen_device_domain_owner *owner; | ||
514 | |||
515 | owner = kzalloc(sizeof(struct xen_device_domain_owner), GFP_KERNEL); | ||
516 | if (!owner) | ||
517 | return -ENODEV; | ||
518 | |||
519 | spin_lock(&dev_domain_list_spinlock); | ||
520 | if (find_device(dev)) { | ||
521 | spin_unlock(&dev_domain_list_spinlock); | ||
522 | kfree(owner); | ||
523 | return -EEXIST; | ||
524 | } | ||
525 | owner->domain = domain; | ||
526 | owner->dev = dev; | ||
527 | list_add_tail(&owner->list, &dev_domain_list); | ||
528 | spin_unlock(&dev_domain_list_spinlock); | ||
529 | return 0; | ||
530 | } | ||
531 | EXPORT_SYMBOL_GPL(xen_register_device_domain_owner); | ||
532 | |||
533 | int xen_unregister_device_domain_owner(struct pci_dev *dev) | ||
534 | { | ||
535 | struct xen_device_domain_owner *owner; | ||
536 | |||
537 | spin_lock(&dev_domain_list_spinlock); | ||
538 | owner = find_device(dev); | ||
539 | if (!owner) { | ||
540 | spin_unlock(&dev_domain_list_spinlock); | ||
541 | return -ENODEV; | ||
542 | } | ||
543 | list_del(&owner->list); | ||
544 | spin_unlock(&dev_domain_list_spinlock); | ||
545 | kfree(owner); | ||
546 | return 0; | ||
547 | } | ||
548 | EXPORT_SYMBOL_GPL(xen_unregister_device_domain_owner); | ||
549 | #endif | ||