xen: fix MSI setup and teardown for PV on HVM guests

When remapping MSIs into pirqs for PV on HVM guests, qemu is responsible
for doing the actual mapping and unmapping.
We only give qemu the desired pirq number when we ask to do the mapping
the first time, after that we should be reading back the pirq number
from qemu every time we want to re-enable the MSI.

This fixes a bug in xen_hvm_setup_msi_irqs that manifests itself when
trying to enable the same MSI for the second time: the old MSI to pirq
mapping is still valid at this point but xen_hvm_setup_msi_irqs would
try to assign a new pirq anyway.
A simple way to reproduce this bug is to assign an MSI capable network
card to a PV on HVM guest, if the user brings down the corresponding
ethernet interface and up again, Linux would fail to enable MSIs on the
device.

Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>

+43 -15
+20 -7
arch/x86/pci/xen.c
··· 70 struct xen_pci_frontend_ops *xen_pci_frontend; 71 EXPORT_SYMBOL_GPL(xen_pci_frontend); 72 73 static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, 74 struct msi_msg *msg) 75 { ··· 86 MSI_ADDR_REDIRECTION_CPU | 87 MSI_ADDR_DEST_ID(pirq); 88 89 - msg->data = 90 - MSI_DATA_TRIGGER_EDGE | 91 - MSI_DATA_LEVEL_ASSERT | 92 - /* delivery mode reserved */ 93 - (3 << 8) | 94 - MSI_DATA_VECTOR(0); 95 } 96 97 static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ··· 96 struct msi_msg msg; 97 98 list_for_each_entry(msidesc, &dev->msi_list, list) { 99 xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? 100 - "msi-x" : "msi", &irq, &pirq); 101 if (irq < 0 || pirq < 0) 102 goto error; 103 printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
··· 70 struct xen_pci_frontend_ops *xen_pci_frontend; 71 EXPORT_SYMBOL_GPL(xen_pci_frontend); 72 73 + #define XEN_PIRQ_MSI_DATA (MSI_DATA_TRIGGER_EDGE | \ 74 + MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0)) 75 + 76 static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq, 77 struct msi_msg *msg) 78 { ··· 83 MSI_ADDR_REDIRECTION_CPU | 84 MSI_ADDR_DEST_ID(pirq); 85 86 + msg->data = XEN_PIRQ_MSI_DATA; 87 } 88 89 static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type) ··· 98 struct msi_msg msg; 99 100 list_for_each_entry(msidesc, &dev->msi_list, list) { 101 + __read_msi_msg(msidesc, &msg); 102 + pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) | 103 + ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff); 104 + if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) { 105 + xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? 106 + "msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ); 107 + if (irq < 0) 108 + goto error; 109 + ret = set_irq_msi(irq, msidesc); 110 + if (ret < 0) 111 + goto error_while; 112 + printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d" 113 + " pirq=%d\n", irq, pirq); 114 + return 0; 115 + } 116 xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ? 117 + "msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ | XEN_ALLOC_PIRQ)); 118 if (irq < 0 || pirq < 0) 119 goto error; 120 printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
+17 -7
drivers/xen/events.c
··· 668 #include <linux/msi.h> 669 #include "../pci/msi.h" 670 671 - void xen_allocate_pirq_msi(char *name, int *irq, int *pirq) 672 { 673 spin_lock(&irq_mapping_update_lock); 674 675 - *irq = find_unbound_irq(); 676 - if (*irq == -1) 677 - goto out; 678 679 - *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI); 680 - if (*pirq == -1) 681 - goto out; 682 683 set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, 684 handle_level_irq, name); ··· 770 printk(KERN_WARNING "unmap irq failed %d\n", rc); 771 goto out; 772 } 773 } 774 irq_info[irq] = mk_unbound_info(); 775 ··· 789 int xen_gsi_from_irq(unsigned irq) 790 { 791 return gsi_from_irq(irq); 792 } 793 794 int bind_evtchn_to_irq(unsigned int evtchn)
··· 668 #include <linux/msi.h> 669 #include "../pci/msi.h" 670 671 + void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc) 672 { 673 spin_lock(&irq_mapping_update_lock); 674 675 + if (alloc & XEN_ALLOC_IRQ) { 676 + *irq = find_unbound_irq(); 677 + if (*irq == -1) 678 + goto out; 679 + } 680 681 + if (alloc & XEN_ALLOC_PIRQ) { 682 + *pirq = find_unbound_pirq(MAP_PIRQ_TYPE_MSI); 683 + if (*pirq == -1) 684 + goto out; 685 + } 686 687 set_irq_chip_and_handler_name(*irq, &xen_pirq_chip, 688 handle_level_irq, name); ··· 766 printk(KERN_WARNING "unmap irq failed %d\n", rc); 767 goto out; 768 } 769 + pirq_to_irq[info->u.pirq.pirq] = -1; 770 } 771 irq_info[irq] = mk_unbound_info(); 772 ··· 784 int xen_gsi_from_irq(unsigned irq) 785 { 786 return gsi_from_irq(irq); 787 + } 788 + 789 + int xen_irq_from_pirq(unsigned pirq) 790 + { 791 + return pirq_to_irq[pirq]; 792 } 793 794 int bind_evtchn_to_irq(unsigned int evtchn)
+6 -1
include/xen/events.h
··· 76 77 #ifdef CONFIG_PCI_MSI 78 /* Allocate an irq and a pirq to be used with MSIs. */ 79 - void xen_allocate_pirq_msi(char *name, int *irq, int *pirq); 80 int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type); 81 #endif 82 ··· 90 91 /* Return gsi allocated to pirq */ 92 int xen_gsi_from_irq(unsigned pirq); 93 94 #endif /* _XEN_EVENTS_H */
··· 76 77 #ifdef CONFIG_PCI_MSI 78 /* Allocate an irq and a pirq to be used with MSIs. */ 79 + #define XEN_ALLOC_PIRQ (1 << 0) 80 + #define XEN_ALLOC_IRQ (1 << 1) 81 + void xen_allocate_pirq_msi(char *name, int *irq, int *pirq, int alloc_mask); 82 int xen_create_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc, int type); 83 #endif 84 ··· 88 89 /* Return gsi allocated to pirq */ 90 int xen_gsi_from_irq(unsigned pirq); 91 + 92 + /* Return irq from pirq */ 93 + int xen_irq_from_pirq(unsigned pirq); 94 95 #endif /* _XEN_EVENTS_H */