# HG changeset patch
# User Jan Beulich <jbeulich@suse.com>
# Date 1318231292 -7200
# Node ID 0b81515b8e982e8012c28e5f8d9e965c63b6503d
# Parent  0c2bfd1f9c6822fbd23af0043f83d93be976323c
passthrough: update bus2bridge mapping as PCI devices get added/removed

This deals with two limitations at once: On device removal, the
mapping did not get updated so far at all, and hotplugged devices as
well as such not discoverable by Xen's initial bus scan (including the
case where a non-zero PCI segment wasn't accessible during Xen boot,
but became accessible after Dom0 validated access information against
ACPI data) wouldn't cause updates to the mapping either.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: "Kay, Allen M" <allen.m.kay@intel.com>

Index: xen-4.1.5-testing/xen/drivers/passthrough/pci.c
===================================================================
--- xen-4.1.5-testing.orig/xen/drivers/passthrough/pci.c
+++ xen-4.1.5-testing/xen/drivers/passthrough/pci.c
@@ -63,11 +63,67 @@ static struct pci_dev *alloc_pdev(u8 bus
     list_add(&pdev->alldevs_list, &alldevs_list);
     spin_lock_init(&pdev->msix_table_lock);
 
+    /* update bus2bridge */
+    switch ( pdev_type(bus, devfn) )
+    {
+        u8 sec_bus, sub_bus;
+
+        case DEV_TYPE_PCIe_BRIDGE:
+            break;
+
+        case DEV_TYPE_PCIe2PCI_BRIDGE:
+        case DEV_TYPE_LEGACY_PCI_BRIDGE:
+            sec_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                                     PCI_SECONDARY_BUS);
+            sub_bus = pci_conf_read8(bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                                     PCI_SUBORDINATE_BUS);
+
+            spin_lock(&bus2bridge_lock);
+            for ( ; sec_bus <= sub_bus; sec_bus++ )
+            {
+                bus2bridge[sec_bus].map = 1;
+                bus2bridge[sec_bus].bus = bus;
+                bus2bridge[sec_bus].devfn = devfn;
+            }
+            spin_unlock(&bus2bridge_lock);
+            break;
+
+        case DEV_TYPE_PCIe_ENDPOINT:
+        case DEV_TYPE_PCI:
+            break;
+
+        default:
+            printk(XENLOG_WARNING "%s: unknown type: %02x:%02x.%u\n",
+                   __func__, bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+            break;
+    }
+
     return pdev;
 }
 
 static void free_pdev(struct pci_dev *pdev)
 {
+    /* update bus2bridge */
+    switch ( pdev_type(pdev->bus, pdev->devfn) )
+    {
+        u8 dev, func, sec_bus, sub_bus;
+
+        case DEV_TYPE_PCIe2PCI_BRIDGE:
+        case DEV_TYPE_LEGACY_PCI_BRIDGE:
+            dev = PCI_SLOT(pdev->devfn);
+            func = PCI_FUNC(pdev->devfn);
+            sec_bus = pci_conf_read8(pdev->bus, dev, func,
+                                     PCI_SECONDARY_BUS);
+            sub_bus = pci_conf_read8(pdev->bus, dev, func,
+                                     PCI_SUBORDINATE_BUS);
+
+            spin_lock(&bus2bridge_lock);
+            for ( ; sec_bus <= sub_bus; sec_bus++ )
+                bus2bridge[sec_bus] = bus2bridge[pdev->bus];
+            spin_unlock(&bus2bridge_lock);
+            break;
+    }
+
     list_del(&pdev->alldevs_list);
     xfree(pdev);
 }
@@ -421,8 +477,6 @@ int __init scan_pci_devices(void)
 {
     struct pci_dev *pdev;
     int bus, dev, func;
-    u8 sec_bus, sub_bus;
-    int type;
 
     spin_lock(&pcidevs_lock);
     for ( bus = 0; bus < 256; bus++ )
@@ -442,41 +496,6 @@ int __init scan_pci_devices(void)
                     return -ENOMEM;
                 }
 
-                /* build bus2bridge */
-                type = pdev_type(bus, PCI_DEVFN(dev, func));
-                switch ( type )
-                {
-                    case DEV_TYPE_PCIe_BRIDGE:
-                        break;
-
-                    case DEV_TYPE_PCIe2PCI_BRIDGE:
-                    case DEV_TYPE_LEGACY_PCI_BRIDGE:
-                        sec_bus = pci_conf_read8(bus, dev, func,
-                                                 PCI_SECONDARY_BUS);
-                        sub_bus = pci_conf_read8(bus, dev, func,
-                                                 PCI_SUBORDINATE_BUS);
-
-                        spin_lock(&bus2bridge_lock);
-                        for ( sub_bus &= 0xff; sec_bus <= sub_bus; sec_bus++ )
-                        {
-                            bus2bridge[sec_bus].map = 1;
-                            bus2bridge[sec_bus].bus =  bus;
-                            bus2bridge[sec_bus].devfn =  PCI_DEVFN(dev, func);
-                        }
-                        spin_unlock(&bus2bridge_lock);
-                        break;
-
-                    case DEV_TYPE_PCIe_ENDPOINT:
-                    case DEV_TYPE_PCI:
-                        break;
-
-                    default:
-                        printk("%s: unknown type: bdf = %x:%x.%x\n",
-                               __func__, bus, dev, func);
-                        spin_unlock(&pcidevs_lock);
-                        return -EINVAL;
-                }
-
                 if ( !func && !(pci_conf_read8(bus, dev, func,
                                                PCI_HEADER_TYPE) & 0x80) )
                     break;
