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"); }