[SeaBIOS] [PATCH 5/5] pci: add prefmem64 region type.
Gerd Hoffmann
kraxel at redhat.com
Thu Feb 16 18:21:36 CET 2012
This patch adds a prefmem64 region type. 64bit prefmem pci bars are
assigned to that region if the device is either on the root bus or if
they are behind a 64bit capable bridge and all other prefmem bars behind
that bridge are 64bit capable too.
The patch also changes the bridge ressource allocation: Unused memory
windows are disabled: If none of the devices connected to the bridge
has -- say -- I/O bars, then the I/O memory window is turned off. This
implies that bridges without devices don't get any ressources assigned.
The pci bridge spec wants us behave that way (figured while looking at
drivers/pci/setup-bus.c in the linux kernel source tree). It also
avoids assigning ressources for both prefmem and prefmem64 ;)
With this patch applied seabios is able to map 64bit bars above 4G.
TODO: detect 64bit capable bridges.
Signed-off-by: Gerd Hoffmann <kraxel at redhat.com>
---
src/acpi-dsdt.dsl | 7 +++
src/config.h | 2 +
src/pciinit.c | 107 +++++++++++++++++++++++++++++++++++++++-------------
3 files changed, 89 insertions(+), 27 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/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 a98f6e3..927e59a 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,6 +44,7 @@ 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;
};
@@ -65,13 +68,17 @@ static u32 pci_index_to_size(int index, enum pci_region_type type)
return 0x1 << (index + shift);
}
-static enum pci_region_type pci_addr_to_type(u32 addr)
+static enum pci_region_type pci_addr_to_type(struct pci_bus *bus, struct pci_bar *bar)
{
- if (addr & PCI_BASE_ADDRESS_SPACE_IO)
+ if (!bar->ismem)
return PCI_REGION_TYPE_IO;
- if (addr & PCI_BASE_ADDRESS_MEM_PREFETCH)
+ if (!bar->isprefetch)
+ return PCI_REGION_TYPE_MEM;
+ if (!bar->is64)
return PCI_REGION_TYPE_PREFMEM;
- return PCI_REGION_TYPE_MEM;
+ if (bus->bus_dev != NULL && !bus->use_prefmem64)
+ return PCI_REGION_TYPE_PREFMEM;
+ return PCI_REGION_TYPE_PREFMEM64;
}
static u32 pci_bar(struct pci_device *pci, int region_num)
@@ -410,11 +417,16 @@ static void pci_bios_check_devices(struct pci_bus *busses)
continue;
bus = &busses[pci->secondary_bus];
bus->bus_dev = pci;
+ /*
+ * TODO: figure whenever the bridge can handle 64bit prefmem
+ * and set bus->use_prefmem64 if so.
+ */
}
// 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 +435,10 @@ 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) {
+ bus->use_prefmem64 = 0;
+ }
+
if (pci->bars[i].is64)
i++;
}
@@ -437,7 +453,7 @@ static void pci_bios_check_devices(struct pci_bus *busses)
if (pci->bars[i].addr == 0)
continue;
- type = pci_addr_to_type(pci->bars[i].addr);
+ type = pci_addr_to_type(bus, &pci->bars[i]);
pci_bios_bus_reserve(bus, type,
pci->bars[i].size);
@@ -457,28 +473,38 @@ static void pci_bios_check_devices(struct pci_bus *busses)
for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
u64 limit = (type == PCI_REGION_TYPE_IO) ?
PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
+ if (s->r[type].sum == 0)
+ continue;
s->r[type].size = s->r[type].sum;
if (s->r[type].size < limit)
s->r[type].size = limit;
s->r[type].size = pci_size_roundup(s->r[type].size);
pci_bios_bus_reserve(parent, type, s->r[type].size);
}
- dprintf(1, "PCI: secondary bus %d sizes: io %llx, mem %llx, prefmem %llx\n",
+ dprintf(1, "PCI: secondary bus %d sizes: 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;
@@ -490,6 +516,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;
}
@@ -504,6 +536,8 @@ static void pci_bios_init_bus_bases(struct pci_bus *bus)
int type, i;
for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
+ if (bus->r[type].sum == 0)
+ continue;
dprintf(1, " type %s max %llx sum %llx base %llx\n", region_type_name[type],
bus->r[type].max, bus->r[type].sum, bus->r[type].base);
base = bus->r[type].base;
@@ -512,7 +546,7 @@ static void pci_bios_init_bus_bases(struct pci_bus *bus)
if (!bus->r[type].count[i])
continue;
newbase = base + size * bus->r[type].count[i];
- dprintf(1, " size %8llx: %d bar(s), %8llx -> %8llx\n",
+ dprintf(1, " size %llx: %d bar(s), %llx -> %llx\n",
size, bus->r[type].count[i], base, newbase - 1);
bus->r[type].bases[i] = base;
base = newbase;
@@ -520,9 +554,10 @@ static void pci_bios_init_bus_bases(struct pci_bus *bus)
}
}
-static u32 pci_bios_bus_get_addr(struct pci_bus *bus, int type, u32 size)
+static u64 pci_bios_bus_get_addr(struct pci_bus *bus, int type, u64 size)
{
- u32 index, addr;
+ u32 index;
+ u64 addr;
index = pci_size_to_index(size, type);
addr = bus->r[type].bases[index];
@@ -550,30 +585,51 @@ static void pci_bios_map_devices(struct pci_bus *busses)
struct pci_bus *parent = &busses[pci_bdf_to_bus(bdf)];
int type;
for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
+ if (s->r[type].sum == 0)
+ continue;
s->r[type].base = pci_bios_bus_get_addr(
parent, type, s->r[type].size);
}
dprintf(1, "PCI: init bases bus %d (secondary)\n", secondary_bus);
pci_bios_init_bus_bases(s);
- u64 base = s->r[PCI_REGION_TYPE_IO].base;
- u64 limit = base + s->r[PCI_REGION_TYPE_IO].size - 1;
+ u64 base, limit;
+ if (s->r[PCI_REGION_TYPE_IO].sum) {
+ base = s->r[PCI_REGION_TYPE_IO].base;
+ limit = base + s->r[PCI_REGION_TYPE_IO].size - 1;
+ } else {
+ base = PCI_BRIDGE_IO_MIN;
+ limit = 0;
+ }
pci_config_writeb(bdf, PCI_IO_BASE, base >> PCI_IO_SHIFT);
pci_config_writew(bdf, PCI_IO_BASE_UPPER16, 0);
pci_config_writeb(bdf, PCI_IO_LIMIT, limit >> PCI_IO_SHIFT);
pci_config_writew(bdf, PCI_IO_LIMIT_UPPER16, 0);
- base = s->r[PCI_REGION_TYPE_MEM].base;
- limit = base + s->r[PCI_REGION_TYPE_MEM].size - 1;
+ if (s->r[PCI_REGION_TYPE_MEM].sum) {
+ base = s->r[PCI_REGION_TYPE_MEM].base;
+ limit = base + s->r[PCI_REGION_TYPE_MEM].size - 1;
+ } else {
+ base = PCI_BRIDGE_MEM_MIN;
+ limit = 0;
+ }
pci_config_writew(bdf, PCI_MEMORY_BASE, base >> PCI_MEMORY_SHIFT);
pci_config_writew(bdf, PCI_MEMORY_LIMIT, limit >> PCI_MEMORY_SHIFT);
- base = s->r[PCI_REGION_TYPE_PREFMEM].base;
- limit = base + s->r[PCI_REGION_TYPE_PREFMEM].size - 1;
+ 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;
+ }
pci_config_writew(bdf, PCI_PREF_MEMORY_BASE, base >> PCI_PREF_MEMORY_SHIFT);
pci_config_writew(bdf, PCI_PREF_MEMORY_LIMIT, limit >> PCI_PREF_MEMORY_SHIFT);
- pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, 0);
- pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, 0);
+ pci_config_writel(bdf, PCI_PREF_BASE_UPPER32, base >> 32);
+ pci_config_writel(bdf, PCI_PREF_LIMIT_UPPER32, base >> 32);
}
// Map regions on each device.
@@ -588,7 +644,7 @@ static void pci_bios_map_devices(struct pci_bus *busses)
if (pci->bars[i].addr == 0)
continue;
- int type = pci_addr_to_type(pci->bars[i].addr);
+ int type = pci_addr_to_type(bus, &pci->bars[i]);
u64 addr = pci_bios_bus_get_addr(bus, type, pci->bars[i].size);
dprintf(1, " bar %d, addr %llx, size %llx [%s]\n",
i, addr, pci->bars[i].size, region_type_name[type]);
@@ -617,9 +673,6 @@ pci_setup(void)
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;
@@ -637,7 +690,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