diff options
Diffstat (limited to 'drivers/xen/events.c')
-rw-r--r-- | drivers/xen/events.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/drivers/xen/events.c b/drivers/xen/events.c index 0ae1d4d7e18c..3ff822b48145 100644 --- a/drivers/xen/events.c +++ b/drivers/xen/events.c | |||
@@ -101,6 +101,7 @@ struct irq_info | |||
101 | unsigned short gsi; | 101 | unsigned short gsi; |
102 | unsigned char vector; | 102 | unsigned char vector; |
103 | unsigned char flags; | 103 | unsigned char flags; |
104 | uint16_t domid; | ||
104 | } pirq; | 105 | } pirq; |
105 | } u; | 106 | } u; |
106 | }; | 107 | }; |
@@ -186,6 +187,7 @@ static void xen_irq_info_pirq_init(unsigned irq, | |||
186 | unsigned short pirq, | 187 | unsigned short pirq, |
187 | unsigned short gsi, | 188 | unsigned short gsi, |
188 | unsigned short vector, | 189 | unsigned short vector, |
190 | uint16_t domid, | ||
189 | unsigned char flags) | 191 | unsigned char flags) |
190 | { | 192 | { |
191 | struct irq_info *info = info_for_irq(irq); | 193 | struct irq_info *info = info_for_irq(irq); |
@@ -195,6 +197,7 @@ static void xen_irq_info_pirq_init(unsigned irq, | |||
195 | info->u.pirq.pirq = pirq; | 197 | info->u.pirq.pirq = pirq; |
196 | info->u.pirq.gsi = gsi; | 198 | info->u.pirq.gsi = gsi; |
197 | info->u.pirq.vector = vector; | 199 | info->u.pirq.vector = vector; |
200 | info->u.pirq.domid = domid; | ||
198 | info->u.pirq.flags = flags; | 201 | info->u.pirq.flags = flags; |
199 | } | 202 | } |
200 | 203 | ||
@@ -656,7 +659,7 @@ int xen_bind_pirq_gsi_to_irq(unsigned gsi, | |||
656 | goto out; | 659 | goto out; |
657 | } | 660 | } |
658 | 661 | ||
659 | xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, | 662 | xen_irq_info_pirq_init(irq, 0, pirq, gsi, irq_op.vector, DOMID_SELF, |
660 | shareable ? PIRQ_SHAREABLE : 0); | 663 | shareable ? PIRQ_SHAREABLE : 0); |
661 | 664 | ||
662 | pirq_query_unmask(irq); | 665 | pirq_query_unmask(irq); |
@@ -707,7 +710,8 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc) | |||
707 | } | 710 | } |
708 | 711 | ||
709 | int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, | 712 | int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, |
710 | int pirq, int vector, const char *name) | 713 | int pirq, int vector, const char *name, |
714 | domid_t domid) | ||
711 | { | 715 | { |
712 | int irq, ret; | 716 | int irq, ret; |
713 | 717 | ||
@@ -720,7 +724,7 @@ int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, | |||
720 | irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq, | 724 | irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq, |
721 | name); | 725 | name); |
722 | 726 | ||
723 | xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, 0); | 727 | xen_irq_info_pirq_init(irq, 0, pirq, 0, vector, domid, 0); |
724 | ret = irq_set_msi_desc(irq, msidesc); | 728 | ret = irq_set_msi_desc(irq, msidesc); |
725 | if (ret < 0) | 729 | if (ret < 0) |
726 | goto error_irq; | 730 | goto error_irq; |
@@ -749,9 +753,16 @@ int xen_destroy_irq(int irq) | |||
749 | 753 | ||
750 | if (xen_initial_domain()) { | 754 | if (xen_initial_domain()) { |
751 | unmap_irq.pirq = info->u.pirq.pirq; | 755 | unmap_irq.pirq = info->u.pirq.pirq; |
752 | unmap_irq.domid = DOMID_SELF; | 756 | unmap_irq.domid = info->u.pirq.domid; |
753 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); | 757 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); |
754 | if (rc) { | 758 | /* If another domain quits without making the pci_disable_msix |
759 | * call, the Xen hypervisor takes care of freeing the PIRQs | ||
760 | * (free_domain_pirqs). | ||
761 | */ | ||
762 | if ((rc == -ESRCH && info->u.pirq.domid != DOMID_SELF)) | ||
763 | printk(KERN_INFO "domain %d does not have %d anymore\n", | ||
764 | info->u.pirq.domid, info->u.pirq.pirq); | ||
765 | else if (rc) { | ||
755 | printk(KERN_WARNING "unmap irq failed %d\n", rc); | 766 | printk(KERN_WARNING "unmap irq failed %d\n", rc); |
756 | goto out; | 767 | goto out; |
757 | } | 768 | } |
@@ -786,6 +797,12 @@ out: | |||
786 | return irq; | 797 | return irq; |
787 | } | 798 | } |
788 | 799 | ||
800 | |||
801 | int xen_pirq_from_irq(unsigned irq) | ||
802 | { | ||
803 | return pirq_from_irq(irq); | ||
804 | } | ||
805 | EXPORT_SYMBOL_GPL(xen_pirq_from_irq); | ||
789 | int bind_evtchn_to_irq(unsigned int evtchn) | 806 | int bind_evtchn_to_irq(unsigned int evtchn) |
790 | { | 807 | { |
791 | int irq; | 808 | int irq; |
@@ -1532,6 +1549,18 @@ void xen_poll_irq(int irq) | |||
1532 | xen_poll_irq_timeout(irq, 0 /* no timeout */); | 1549 | xen_poll_irq_timeout(irq, 0 /* no timeout */); |
1533 | } | 1550 | } |
1534 | 1551 | ||
1552 | /* Check whether the IRQ line is shared with other guests. */ | ||
1553 | int xen_test_irq_shared(int irq) | ||
1554 | { | ||
1555 | struct irq_info *info = info_for_irq(irq); | ||
1556 | struct physdev_irq_status_query irq_status = { .irq = info->u.pirq.pirq }; | ||
1557 | |||
1558 | if (HYPERVISOR_physdev_op(PHYSDEVOP_irq_status_query, &irq_status)) | ||
1559 | return 0; | ||
1560 | return !(irq_status.flags & XENIRQSTAT_shared); | ||
1561 | } | ||
1562 | EXPORT_SYMBOL_GPL(xen_test_irq_shared); | ||
1563 | |||
1535 | void xen_irq_resume(void) | 1564 | void xen_irq_resume(void) |
1536 | { | 1565 | { |
1537 | unsigned int cpu, evtchn; | 1566 | unsigned int cpu, evtchn; |