]> git.karo-electronics.de Git - linux-beck.git/blobdiff - arch/x86/pci/xen.c
Merge branches 'x86-fixes-for-linus', 'perf-fixes-for-linus' and 'sched-fixes-for...
[linux-beck.git] / arch / x86 / pci / xen.c
index 117f5b8daf7515bf8ac03deb5522a011c286280d..25cd4a07d09f78cbe850733f0d2d36d98fe5d176 100644 (file)
@@ -70,6 +70,9 @@ static int acpi_register_gsi_xen_hvm(struct device *dev, u32 gsi,
 struct xen_pci_frontend_ops *xen_pci_frontend;
 EXPORT_SYMBOL_GPL(xen_pci_frontend);
 
+#define XEN_PIRQ_MSI_DATA  (MSI_DATA_TRIGGER_EDGE | \
+               MSI_DATA_LEVEL_ASSERT | (3 << 8) | MSI_DATA_VECTOR(0))
+
 static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
                struct msi_msg *msg)
 {
@@ -83,12 +86,7 @@ static void xen_msi_compose_msg(struct pci_dev *pdev, unsigned int pirq,
                MSI_ADDR_REDIRECTION_CPU |
                MSI_ADDR_DEST_ID(pirq);
 
-       msg->data =
-               MSI_DATA_TRIGGER_EDGE |
-               MSI_DATA_LEVEL_ASSERT |
-               /* delivery mode reserved */
-               (3 << 8) |
-               MSI_DATA_VECTOR(0);
+       msg->data = XEN_PIRQ_MSI_DATA;
 }
 
 static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
@@ -98,8 +96,23 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
        struct msi_msg msg;
 
        list_for_each_entry(msidesc, &dev->msi_list, list) {
+               __read_msi_msg(msidesc, &msg);
+               pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
+                       ((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
+               if (xen_irq_from_pirq(pirq) >= 0 && msg.data == XEN_PIRQ_MSI_DATA) {
+                       xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
+                                       "msi-x" : "msi", &irq, &pirq, XEN_ALLOC_IRQ);
+                       if (irq < 0)
+                               goto error;
+                       ret = set_irq_msi(irq, msidesc);
+                       if (ret < 0)
+                               goto error_while;
+                       printk(KERN_DEBUG "xen: msi already setup: msi --> irq=%d"
+                                       " pirq=%d\n", irq, pirq);
+                       return 0;
+               }
                xen_allocate_pirq_msi((type == PCI_CAP_ID_MSIX) ?
-                               "msi-x" : "msi", &irq, &pirq);
+                               "msi-x" : "msi", &irq, &pirq, (XEN_ALLOC_IRQ | XEN_ALLOC_PIRQ));
                if (irq < 0 || pirq < 0)
                        goto error;
                printk(KERN_DEBUG "xen: msi --> irq=%d, pirq=%d\n", irq, pirq);
@@ -147,8 +160,10 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                irq = xen_allocate_pirq(v[i], 0, /* not sharable */
                        (type == PCI_CAP_ID_MSIX) ?
                        "pcifront-msi-x" : "pcifront-msi");
-               if (irq < 0)
-                       return -1;
+               if (irq < 0) {
+                       ret = -1;
+                       goto free;
+               }
 
                ret = set_irq_msi(irq, msidesc);
                if (ret)
@@ -164,7 +179,7 @@ error:
        if (ret == -ENODEV)
                dev_err(&dev->dev, "Xen PCI frontend has not registered" \
                        " MSI/MSI-X support!\n");
-
+free:
        kfree(v);
        return ret;
 }