[SeaBIOS] [PATCH 2/2] fw/pci: map memory and IO regions for multiple pci root buses

Marcel Apfelbaum marcel.a at redhat.com
Mon Nov 24 10:47:51 CET 2014


Removed the assumption that the system has only one primary root bus.
When mapping memory and IO regions go over all buses, skipping
secondary and absent buses.

Signed-off-by: Marcel Apfelbaum <marcel.a at redhat.com>
---
 src/fw/pciinit.c | 114 ++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 79 insertions(+), 35 deletions(-)

diff --git a/src/fw/pciinit.c b/src/fw/pciinit.c
index a5f6505..97b1af6 100644
--- a/src/fw/pciinit.c
+++ b/src/fw/pciinit.c
@@ -763,43 +763,80 @@ static int pci_bios_init_root_regions_io(struct pci_bus *bus)
      *                    where they want, on older versions its fixed ]
      *   c000 - ffff    free, traditionally used for pci io
      */
-    struct pci_region *r_io = &bus->r[PCI_REGION_TYPE_IO];
-    u64 sum = pci_region_sum(r_io);
-    if (sum < 0x4000) {
-        /* traditional region is big enougth, use it */
-        r_io->base = 0xc000;
-    } else if (sum < pci_io_low_end - 0x1000) {
-        /* use the larger region at 0x1000 */
-        r_io->base = 0x1000;
-    } else {
-        /* not enouth io address space -> error out */
-        return -1;
+
+    u64 sum_pci = 0;  /* c000 - ffff */
+    u64 sum_free = 0; /* 1000 - 9fff */
+    int i;
+
+    for (i = 0; i <= MaxPCIBus; i++) {
+        struct pci_region *r_io = &bus[i].r[PCI_REGION_TYPE_IO];
+        u64 sum = pci_region_sum(r_io);
+        if (bus[i].bus_dev || !sum)
+            continue;
+
+        sum_pci = ALIGN(sum_pci, sum);
+        sum_free = ALIGN(sum_free, sum);
+        if (sum + sum_pci < 0x4000) {
+            /* traditional region is big enough, use it */
+            r_io->base = 0xc000 + sum_pci;
+            sum_pci += sum;
+        } else if (sum < pci_io_low_end - 0x1000 - sum_free) {
+            /* use the larger region at 0x1000 */
+            r_io->base = 0x1000 + sum_free;
+            sum_free += sum;
+        } else {
+            /* not enough io address space -> error out */
+            return -1;
+        }
+
+        if (sum) {
+            dprintf(1, "PCI: BUS %d IO: %4llx - %4llx\n",
+                    i, r_io->base, r_io->base + sum - 1);
+        }
     }
-    dprintf(1, "PCI: IO: %4llx - %4llx\n", r_io->base, r_io->base + sum - 1);
     return 0;
 }
 
 static int pci_bios_init_root_regions_mem(struct pci_bus *bus)
 {
-    struct pci_region *r_end = &bus->r[PCI_REGION_TYPE_PREFMEM];
-    struct pci_region *r_start = &bus->r[PCI_REGION_TYPE_MEM];
-
-    if (pci_region_align(r_start) < pci_region_align(r_end)) {
-        // Swap regions to improve alignment.
-        r_end = r_start;
-        r_start = &bus->r[PCI_REGION_TYPE_PREFMEM];
-    }
-    u64 sum = pci_region_sum(r_end);
-    u64 align = pci_region_align(r_end);
-    r_end->base = ALIGN_DOWN((pcimem_end - sum), align);
-    sum = pci_region_sum(r_start);
-    align = pci_region_align(r_start);
-    r_start->base = ALIGN_DOWN((r_end->base - sum), align);
-
-    if ((r_start->base < pcimem_start) ||
-         (r_start->base > pcimem_end))
-        // Memory range requested is larger than available.
-        return -1;
+    u64 region_end = pcimem_end;
+    int i;
+
+    for (i = 0; i <= MaxPCIBus; i++) {
+        struct pci_region *r_end = &bus[i].r[PCI_REGION_TYPE_PREFMEM];
+        struct pci_region *r_start = &bus[i].r[PCI_REGION_TYPE_MEM];
+
+        if (pci_region_align(r_start) < pci_region_align(r_end)) {
+            // Swap regions to improve alignment.
+            r_end = r_start;
+            r_start = &bus[i].r[PCI_REGION_TYPE_PREFMEM];
+        }
+
+        u64 sum = pci_region_sum(r_end);
+        if (bus[i].bus_dev || !sum)
+            continue;
+
+        u64 align = pci_region_align(r_end);
+        r_end->base = ALIGN_DOWN((region_end - sum), align);
+
+        dprintf(1, "PCI: BUS %d MEM: %4llx - %4llx\n",
+                i, r_end->base, r_end->base + sum - 1);
+
+        sum = pci_region_sum(r_start);
+        align = pci_region_align(r_start);
+        r_start->base = ALIGN_DOWN((r_end->base - sum), align);
+        region_end = r_start->base;
+
+        dprintf(1, "PCI: BUS %d MEM: %4llx - %4llx\n",
+                i, r_start->base, r_start->base + sum - 1);
+
+        if ((r_start->base < pcimem_start) ||
+             (r_start->base > pcimem_end))
+            // Memory range requested is larger than available.
+            return -1;
+
+    }
+
     return 0;
 }
 
@@ -864,12 +901,19 @@ static void pci_bios_map_devices(struct pci_bus *busses)
     dprintf(1, "PCI: 32: %016llx - %016llx\n", pcimem_start, pcimem_end);
     if (pci_bios_init_root_regions_mem(busses)) {
         struct pci_region r64_mem, r64_pref;
+        int i;
         r64_mem.list.first = NULL;
         r64_pref.list.first = NULL;
-        pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_MEM],
-                                         &r64_mem);
-        pci_region_migrate_64bit_entries(&busses[0].r[PCI_REGION_TYPE_PREFMEM],
-                                         &r64_pref);
+
+        for (i = 0; i <= MaxPCIBus; i++) {
+            if (busses[i].bus_dev)
+                continue;
+
+            pci_region_migrate_64bit_entries(&busses[i].r[PCI_REGION_TYPE_MEM],
+                                             &r64_mem);
+            pci_region_migrate_64bit_entries(&busses[i].r[PCI_REGION_TYPE_PREFMEM],
+                                             &r64_pref);
+        }
 
         if (pci_bios_init_root_regions_mem(busses))
             panic("PCI: out of 32bit address space\n");
-- 
1.9.3




More information about the SeaBIOS mailing list