[SeaBIOS] [PATCH v2 6/6] pci: add prefmem64

Gerd Hoffmann kraxel at redhat.com
Wed Feb 29 12:45:10 CET 2012


This patch adds a prefmem64 region for 64bit pci prefmem bars which
we'll go map above 4G.  This will happen when either the device is on
the root bus or it is behind a bridge supporting 64bit memory windows
and all prefmem bars of all devices hooked up using that bridge are
64bit capable.
---
 src/acpi-dsdt.dsl |    7 +++++
 src/acpi-dsdt.hex |   72 +++++++++++++++++++++++++++++++++++++++++++---------
 src/config.h      |    2 +
 src/pciinit.c     |   72 +++++++++++++++++++++++++++++++++++++++++++---------
 4 files changed, 127 insertions(+), 26 deletions(-)

diff --git a/src/acpi-dsdt.dsl b/src/acpi-dsdt.dsl
index 7082b65..c17e947 100644
--- a/src/acpi-dsdt.dsl
+++ b/src/acpi-dsdt.dsl
@@ -175,6 +175,13 @@ DefinitionBlock (
                     0x00000000,         // Address Translation Offset
                     0x1EC00000,         // Address Length
                     ,, , AddressRangeMemory, TypeStatic)
+                QWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
+                    0x00000000,          // Address Space Granularity
+                    0x8000000000,        // Address Range Minimum
+                    0xFFFFFFFFFF,        // Address Range Maximum
+                    0x00000000,          // Address Translation Offset
+                    0x8000000000,        // Address Length
+                    ,, , AddressRangeMemory, TypeStatic)
             })
         }
     }
diff --git a/src/acpi-dsdt.hex b/src/acpi-dsdt.hex
index 5dc7bb4..2393827 100644
--- a/src/acpi-dsdt.hex
+++ b/src/acpi-dsdt.hex
@@ -3,12 +3,12 @@ static unsigned char AmlCode[] = {
 0x53,
 0x44,
 0x54,
-0xd3,
-0x10,
+0x1,
+0x11,
 0x0,
 0x0,
 0x1,
-0x2d,
+0x1e,
 0x42,
 0x58,
 0x50,
@@ -31,9 +31,9 @@ static unsigned char AmlCode[] = {
 0x4e,
 0x54,
 0x4c,
-0x28,
-0x5,
-0x10,
+0x23,
+0x1,
+0x9,
 0x20,
 0x10,
 0x49,
@@ -110,16 +110,16 @@ static unsigned char AmlCode[] = {
 0x47,
 0x42,
 0x10,
-0x44,
-0x81,
+0x42,
+0x84,
 0x5f,
 0x53,
 0x42,
 0x5f,
 0x5b,
 0x82,
-0x4c,
-0x80,
+0x4a,
+0x83,
 0x50,
 0x43,
 0x49,
@@ -2064,10 +2064,10 @@ static unsigned char AmlCode[] = {
 0x52,
 0x53,
 0x11,
-0x42,
-0x7,
+0x40,
+0xa,
 0xa,
-0x6e,
+0x9c,
 0x88,
 0xd,
 0x0,
@@ -2176,6 +2176,52 @@ static unsigned char AmlCode[] = {
 0x0,
 0xc0,
 0x1e,
+0x8a,
+0x2b,
+0x0,
+0x0,
+0xc,
+0x3,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x80,
+0x0,
+0x0,
+0x0,
+0xff,
+0xff,
+0xff,
+0xff,
+0xff,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x0,
+0x80,
+0x0,
+0x0,
+0x0,
 0x79,
 0x0,
 0x10,
diff --git a/src/config.h b/src/config.h
index b0187a4..5850476 100644
--- a/src/config.h
+++ b/src/config.h
@@ -47,6 +47,8 @@
 
 #define BUILD_PCIMEM_START        0xe0000000
 #define BUILD_PCIMEM_END          0xfec00000    /* IOAPIC is mapped at */
+#define BUILD_PCIMEM64_START      0x8000000000ULL
+#define BUILD_PCIMEM64_END        0xFFFFFFFFFFULL
 
 #define BUILD_IOAPIC_ADDR         0xfec00000
 #define BUILD_HPET_ADDRESS        0xfed00000
diff --git a/src/pciinit.c b/src/pciinit.c
index a03e17c..b3eaf86 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -22,13 +22,15 @@ enum pci_region_type {
     PCI_REGION_TYPE_IO,
     PCI_REGION_TYPE_MEM,
     PCI_REGION_TYPE_PREFMEM,
+    PCI_REGION_TYPE_PREFMEM64,
     PCI_REGION_TYPE_COUNT,
 };
 
 static const char *region_type_name[] = {
-    [ PCI_REGION_TYPE_IO ]      = "io",
-    [ PCI_REGION_TYPE_MEM ]     = "mem",
-    [ PCI_REGION_TYPE_PREFMEM ] = "prefmem",
+    [ PCI_REGION_TYPE_IO ]        = "io",
+    [ PCI_REGION_TYPE_MEM ]       = "mem",
+    [ PCI_REGION_TYPE_PREFMEM ]   = "prefmem",
+    [ PCI_REGION_TYPE_PREFMEM64 ] = "prefmem64",
 };
 
 struct pci_bus {
@@ -42,7 +44,9 @@ struct pci_bus {
         u64 bases[32 - PCI_MEM_INDEX_SHIFT];
         u64 base;
     } r[PCI_REGION_TYPE_COUNT];
+    int use_prefmem64;
     struct pci_device *bus_dev;
+    struct pci_bus *parent;
 };
 
 static int pci_size_to_index(u32 size, enum pci_region_type type)
@@ -67,11 +71,19 @@ static u32 pci_index_to_size(int index, enum pci_region_type type)
 
 static enum pci_region_type pci_addr_to_type(struct pci_bus *bus, struct pci_bar *bar)
 {
+    struct pci_bus *b;
+
     if (!bar->ismem)
         return PCI_REGION_TYPE_IO;
     if (!bar->isprefetch)
         return PCI_REGION_TYPE_MEM;
-    return PCI_REGION_TYPE_PREFMEM;
+    if (!bar->is64)
+        return PCI_REGION_TYPE_PREFMEM;
+    for (b = bus; b != NULL && b->bus_dev != NULL; b = b->parent) {
+        if (!bus->use_prefmem64)
+            return PCI_REGION_TYPE_PREFMEM;
+    }
+    return PCI_REGION_TYPE_PREFMEM64;
 }
 
 static u32 pci_bar(struct pci_device *pci, int region_num)
@@ -409,12 +421,26 @@ static void pci_bios_check_devices(struct pci_bus *busses)
         if (pci->class != PCI_CLASS_BRIDGE_PCI)
             continue;
         bus = &busses[pci->secondary_bus];
+        bus->parent = &busses[pci_bdf_to_bus(pci->bdf)];
         bus->bus_dev = pci;
+        u32 pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
+        if (!pmem) {
+            pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0xfff0fff0);
+            pmem = pci_config_readl(pci->bdf, PCI_PREF_MEMORY_BASE);
+            pci_config_writel(pci->bdf, PCI_PREF_MEMORY_BASE, 0x0);
+        }
+        if ((pmem & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
+            dprintf(1, "PCI: bridge bdf=%02x:%02x.%x supports prefmem64\n",
+                    pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
+                    pci_bdf_to_fn(pci->bdf));
+            bus->use_prefmem64 = 1;
+        }
     }
 
     // discover pci bars
     foreachpci(pci) {
         num_regions = (pci->class == PCI_CLASS_BRIDGE_PCI) ? 2 : PCI_NUM_REGIONS;
+        bus = &busses[pci_bdf_to_bus(pci->bdf)];
         dprintf(1, "PCI: check device bdf=%02x:%02x.%x\n",
                 pci_bdf_to_bus(pci->bdf), pci_bdf_to_dev(pci->bdf),
                 pci_bdf_to_fn(pci->bdf));
@@ -423,6 +449,15 @@ static void pci_bios_check_devices(struct pci_bus *busses)
             if (pci->bars[i].addr == 0)
                 continue;
 
+            if (pci->bars[i].ismem && pci->bars[i].isprefetch && !pci->bars[i].is64) {
+                /* 32bit prefmem bar found -- disable 64bit prefmem
+                 * on all bridges all the way up to the root bus */
+                struct pci_bus *b;
+                for (b = bus; b != NULL; b = b->parent) {
+                    b->use_prefmem64 = 0;
+                }
+            }
+
             if (pci->bars[i].is64)
                 i++;
         }
@@ -466,22 +501,29 @@ static void pci_bios_check_devices(struct pci_bus *busses)
             pci_bios_bus_reserve(parent, type, s->r[type].size);
         }
         dprintf(1, "PCI: secondary bus %d sizes: "
-                "io %llx, mem %llx, prefmem %llx\n",
+                "io %llx, mem %llx, prefmem %llx, prefmem64 %llx\n",
                 secondary_bus,
                 s->r[PCI_REGION_TYPE_IO].size,
                 s->r[PCI_REGION_TYPE_MEM].size,
-                s->r[PCI_REGION_TYPE_PREFMEM].size);
+                s->r[PCI_REGION_TYPE_PREFMEM].size,
+                s->r[PCI_REGION_TYPE_PREFMEM64].size);
     }
 }
 
 #define ROOT_BASE(top, sum, max) ALIGN_DOWN((top)-(sum),(max) ?: 1)
 
 // Setup region bases (given the regions' size and alignment)
-static int pci_bios_init_root_regions(struct pci_bus *bus, u32 start, u32 end)
+static int pci_bios_init_root_regions(struct pci_bus *bus)
 {
+    u32 start = BUILD_PCIMEM_START;
+    u32 end = BUILD_PCIMEM_END;
+    u64 start64 = BUILD_PCIMEM64_START;
+    u64 end64 = BUILD_PCIMEM64_END;
+
     bus->r[PCI_REGION_TYPE_IO].base = 0xc000;
 
     int reg1 = PCI_REGION_TYPE_PREFMEM, reg2 = PCI_REGION_TYPE_MEM;
+    int reg3 = PCI_REGION_TYPE_PREFMEM64;
     if (bus->r[reg1].sum < bus->r[reg2].sum) {
         // Swap regions so larger area is more likely to align well.
         reg1 = PCI_REGION_TYPE_MEM;
@@ -493,6 +535,12 @@ static int pci_bios_init_root_regions(struct pci_bus *bus, u32 start, u32 end)
     if (bus->r[reg1].base < start)
         // Memory range requested is larger than available.
         return -1;
+
+    bus->r[reg3].base = ROOT_BASE(end64, bus->r[reg3].sum, bus->r[reg3].max);
+    if (bus->r[reg3].base < start64)
+        // Memory range requested is larger than available.
+        return -1;
+
     return 0;
 }
 
@@ -591,6 +639,9 @@ static void pci_bios_map_devices(struct pci_bus *busses)
         if (s->r[PCI_REGION_TYPE_PREFMEM].sum) {
             base = s->r[PCI_REGION_TYPE_PREFMEM].base;
             limit = base + s->r[PCI_REGION_TYPE_PREFMEM].size - 1;
+        } else if (s->r[PCI_REGION_TYPE_PREFMEM64].sum) {
+            base = s->r[PCI_REGION_TYPE_PREFMEM64].base;
+            limit = base + s->r[PCI_REGION_TYPE_PREFMEM64].size - 1;
         } else {
             base = PCI_BRIDGE_MEM_MIN;
             limit = 0;
@@ -641,11 +692,6 @@ pci_setup(void)
         return;
     }
 
-    dprintf(3, "pci setup\n");
-
-    u32 start = BUILD_PCIMEM_START;
-    u32 end   = BUILD_PCIMEM_END;
-
     dprintf(1, "=== PCI bus & bridge init ===\n");
     if (pci_probe_host() != 0) {
         return;
@@ -663,7 +709,7 @@ pci_setup(void)
     }
     memset(busses, 0, sizeof(*busses) * (MaxPCIBus + 1));
     pci_bios_check_devices(busses);
-    if (pci_bios_init_root_regions(&busses[0], start, end) != 0) {
+    if (pci_bios_init_root_regions(&busses[0]) != 0) {
         panic("PCI: out of address space\n");
     }
 
-- 
1.7.1




More information about the SeaBIOS mailing list