Merge branches 'stable/drivers-3.2', 'stable/drivers.bugfixes-3.2' and 'stable/pci...
[pandora-kernel.git] / arch / x86 / pci / xen.c
index 1017c7b..492ade8 100644 (file)
@@ -175,8 +175,10 @@ static int xen_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                                               "pcifront-msi-x" :
                                               "pcifront-msi",
                                                DOMID_SELF);
-               if (irq < 0)
+               if (irq < 0) {
+                       ret = irq;
                        goto free;
+               }
                i++;
        }
        kfree(v);
@@ -221,8 +223,10 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                if (msg.data != XEN_PIRQ_MSI_DATA ||
                    xen_irq_from_pirq(pirq) < 0) {
                        pirq = xen_allocate_pirq_msi(dev, msidesc);
-                       if (pirq < 0)
+                       if (pirq < 0) {
+                               irq = -ENODEV;
                                goto error;
+                       }
                        xen_msi_compose_msg(dev, pirq, &msg);
                        __write_msi_msg(msidesc, &msg);
                        dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
@@ -244,10 +248,12 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 error:
        dev_err(&dev->dev,
                "Xen PCI frontend has not registered MSI/MSI-X support!\n");
-       return -ENODEV;
+       return irq;
 }
 
 #ifdef CONFIG_XEN_DOM0
+static bool __read_mostly pci_seg_supported = true;
+
 static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 {
        int ret = 0;
@@ -265,10 +271,11 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
 
                memset(&map_irq, 0, sizeof(map_irq));
                map_irq.domid = domid;
-               map_irq.type = MAP_PIRQ_TYPE_MSI;
+               map_irq.type = MAP_PIRQ_TYPE_MSI_SEG;
                map_irq.index = -1;
                map_irq.pirq = -1;
-               map_irq.bus = dev->bus->number;
+               map_irq.bus = dev->bus->number |
+                             (pci_domain_nr(dev->bus) << 16);
                map_irq.devfn = dev->devfn;
 
                if (type == PCI_CAP_ID_MSIX) {
@@ -285,7 +292,20 @@ static int xen_initdom_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
                        map_irq.entry_nr = msidesc->msi_attrib.entry_nr;
                }
 
-               ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq, &map_irq);
+               ret = -EINVAL;
+               if (pci_seg_supported)
+                       ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq,
+                                                   &map_irq);
+               if (ret == -EINVAL && !pci_domain_nr(dev->bus)) {
+                       map_irq.type = MAP_PIRQ_TYPE_MSI;
+                       map_irq.index = -1;
+                       map_irq.pirq = -1;
+                       map_irq.bus = dev->bus->number;
+                       ret = HYPERVISOR_physdev_op(PHYSDEVOP_map_pirq,
+                                                   &map_irq);
+                       if (ret != -EINVAL)
+                               pci_seg_supported = false;
+               }
                if (ret) {
                        dev_warn(&dev->dev, "xen map irq failed %d for %d domain\n",
                                 ret, domid);