diff options
Diffstat (limited to 'drivers/xen/events/events_base.c')
-rw-r--r-- | drivers/xen/events/events_base.c | 47 |
1 files changed, 32 insertions, 15 deletions
diff --git a/drivers/xen/events/events_base.c b/drivers/xen/events/events_base.c index 9875d6ec1063..793053065629 100644 --- a/drivers/xen/events/events_base.c +++ b/drivers/xen/events/events_base.c | |||
@@ -391,10 +391,10 @@ static void xen_irq_init(unsigned irq) | |||
391 | list_add_tail(&info->list, &xen_irq_list_head); | 391 | list_add_tail(&info->list, &xen_irq_list_head); |
392 | } | 392 | } |
393 | 393 | ||
394 | static int __must_check xen_allocate_irq_dynamic(void) | 394 | static int __must_check xen_allocate_irqs_dynamic(int nvec) |
395 | { | 395 | { |
396 | int first = 0; | 396 | int first = 0; |
397 | int irq; | 397 | int i, irq; |
398 | 398 | ||
399 | #ifdef CONFIG_X86_IO_APIC | 399 | #ifdef CONFIG_X86_IO_APIC |
400 | /* | 400 | /* |
@@ -408,14 +408,22 @@ static int __must_check xen_allocate_irq_dynamic(void) | |||
408 | first = get_nr_irqs_gsi(); | 408 | first = get_nr_irqs_gsi(); |
409 | #endif | 409 | #endif |
410 | 410 | ||
411 | irq = irq_alloc_desc_from(first, -1); | 411 | irq = irq_alloc_descs_from(first, nvec, -1); |
412 | 412 | ||
413 | if (irq >= 0) | 413 | if (irq >= 0) { |
414 | xen_irq_init(irq); | 414 | for (i = 0; i < nvec; i++) |
415 | xen_irq_init(irq + i); | ||
416 | } | ||
415 | 417 | ||
416 | return irq; | 418 | return irq; |
417 | } | 419 | } |
418 | 420 | ||
421 | static inline int __must_check xen_allocate_irq_dynamic(void) | ||
422 | { | ||
423 | |||
424 | return xen_allocate_irqs_dynamic(1); | ||
425 | } | ||
426 | |||
419 | static int __must_check xen_allocate_irq_gsi(unsigned gsi) | 427 | static int __must_check xen_allocate_irq_gsi(unsigned gsi) |
420 | { | 428 | { |
421 | int irq; | 429 | int irq; |
@@ -738,22 +746,25 @@ int xen_allocate_pirq_msi(struct pci_dev *dev, struct msi_desc *msidesc) | |||
738 | } | 746 | } |
739 | 747 | ||
740 | int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, | 748 | int xen_bind_pirq_msi_to_irq(struct pci_dev *dev, struct msi_desc *msidesc, |
741 | int pirq, const char *name, domid_t domid) | 749 | int pirq, int nvec, const char *name, domid_t domid) |
742 | { | 750 | { |
743 | int irq, ret; | 751 | int i, irq, ret; |
744 | 752 | ||
745 | mutex_lock(&irq_mapping_update_lock); | 753 | mutex_lock(&irq_mapping_update_lock); |
746 | 754 | ||
747 | irq = xen_allocate_irq_dynamic(); | 755 | irq = xen_allocate_irqs_dynamic(nvec); |
748 | if (irq < 0) | 756 | if (irq < 0) |
749 | goto out; | 757 | goto out; |
750 | 758 | ||
751 | irq_set_chip_and_handler_name(irq, &xen_pirq_chip, handle_edge_irq, | 759 | for (i = 0; i < nvec; i++) { |
752 | name); | 760 | irq_set_chip_and_handler_name(irq + i, &xen_pirq_chip, handle_edge_irq, name); |
761 | |||
762 | ret = xen_irq_info_pirq_setup(irq + i, 0, pirq + i, 0, domid, | ||
763 | i == 0 ? 0 : PIRQ_MSI_GROUP); | ||
764 | if (ret < 0) | ||
765 | goto error_irq; | ||
766 | } | ||
753 | 767 | ||
754 | ret = xen_irq_info_pirq_setup(irq, 0, pirq, 0, domid, 0); | ||
755 | if (ret < 0) | ||
756 | goto error_irq; | ||
757 | ret = irq_set_msi_desc(irq, msidesc); | 768 | ret = irq_set_msi_desc(irq, msidesc); |
758 | if (ret < 0) | 769 | if (ret < 0) |
759 | goto error_irq; | 770 | goto error_irq; |
@@ -761,7 +772,8 @@ out: | |||
761 | mutex_unlock(&irq_mapping_update_lock); | 772 | mutex_unlock(&irq_mapping_update_lock); |
762 | return irq; | 773 | return irq; |
763 | error_irq: | 774 | error_irq: |
764 | __unbind_from_irq(irq); | 775 | for (; i >= 0; i--) |
776 | __unbind_from_irq(irq + i); | ||
765 | mutex_unlock(&irq_mapping_update_lock); | 777 | mutex_unlock(&irq_mapping_update_lock); |
766 | return ret; | 778 | return ret; |
767 | } | 779 | } |
@@ -780,7 +792,12 @@ int xen_destroy_irq(int irq) | |||
780 | if (!desc) | 792 | if (!desc) |
781 | goto out; | 793 | goto out; |
782 | 794 | ||
783 | if (xen_initial_domain()) { | 795 | /* |
796 | * If trying to remove a vector in a MSI group different | ||
797 | * than the first one skip the PIRQ unmap unless this vector | ||
798 | * is the first one in the group. | ||
799 | */ | ||
800 | if (xen_initial_domain() && !(info->u.pirq.flags & PIRQ_MSI_GROUP)) { | ||
784 | unmap_irq.pirq = info->u.pirq.pirq; | 801 | unmap_irq.pirq = info->u.pirq.pirq; |
785 | unmap_irq.domid = info->u.pirq.domid; | 802 | unmap_irq.domid = info->u.pirq.domid; |
786 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); | 803 | rc = HYPERVISOR_physdev_op(PHYSDEVOP_unmap_pirq, &unmap_irq); |