[SeaBIOS] [PATCH 3/6] Fill PCI regions with etnries
Alexey Korolev
alexey.korolev at endace.com
Thu Mar 1 07:40:59 CET 2012
In this patch we fill pci_regions with entries.
The idea of implementation is pretty much the same as it was before in pci_check_devices()
function.
The pci_bios_fill_regions() function scans pci devices.
1) If pci device is a pci-to-pci bridge
a) we create empty entry.
b) Associate new entry with pci_region, which is provided by pci-to-pci bridge
c) Add new entry to a list of pci_region of parent bus.
2) If pci device is not a bridge.
a) Scan PCI BARs.
b) Get size and attributes. (Type and is64bit)
c) Add new entry to a list of pci_region of parent bus.
Then the pci_bios_fill_regions() scans pci_regions in reverse order
to calculate size of pci_region_entries belonging to a bridge.
Signed-off-by: Alexey Korolev <alexey.korolev at endace.com>
---
src/pciinit.c | 103 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 98 insertions(+), 5 deletions(-)
diff --git a/src/pciinit.c b/src/pciinit.c
index b02da89..03ece34 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -12,11 +12,10 @@
#include "pci_regs.h" // PCI_COMMAND
#include "xen.h" // usingXen
-#define PCI_IO_INDEX_SHIFT 2
-#define PCI_MEM_INDEX_SHIFT 12
-
-#define PCI_BRIDGE_IO_MIN 0x1000
-#define PCI_BRIDGE_MEM_MIN 0x100000
+#define PCI_DEV_IO_MINSIZE 4
+#define PCI_DEV_MEM_MINSIZE 0x1000
+#define PCI_BRIDGE_IO_MINSIZE 0x1000
+#define PCI_BRIDGE_MEM_MINSIZE 0x100000
enum pci_region_type {
PCI_REGION_TYPE_IO,
@@ -408,6 +407,96 @@ dump_entry(struct pci_region_entry *entry)
region_type_name[entry->type],entry->is64bit ? "64bits" : "32bits");
}
+/****************************************************************
+ * Build topology and calculate size of entries
+ ****************************************************************/
+struct pci_region_entry *
+pci_region_create_entry(struct pci_region *parent, struct pci_device *dev,
+ u64 size, int type, int is64bit)
+{
+ struct pci_region_entry *entry= malloc_tmp(sizeof(*entry));
+ if (!entry) {
+ warn_noalloc();
+ return NULL;
+ }
+ memset(entry, 0, sizeof(*entry));
+
+ entry->dev = dev;
+ entry->type = type;
+ entry->is64bit = is64bit;
+ entry->size = size;
+ region_entry_add(parent, entry);
+ entry->parent_region = parent;
+ return entry;
+}
+
+static int pci_bios_fill_regions(struct pci_region *regions)
+{
+ struct pci_region *this_region, *parent;
+ enum pci_region_type type;
+ struct pci_device *pci;
+ struct pci_region_entry *entry;
+ int is64bit, i;
+ u64 size, min_size;
+
+ foreachpci(pci) {
+ if (pci->class == PCI_CLASS_BRIDGE_PCI) {
+ this_region = ®ions[pci->secondary_bus * PCI_REGION_TYPE_COUNT];
+ parent = ®ions[pci_bdf_to_bus(pci->bdf) * PCI_REGION_TYPE_COUNT];
+ for (type = 0; type < PCI_REGION_TYPE_COUNT;
+ type++, this_region++, parent++) {
+ /* Only prefetchable bridge regions can be 64bit */
+ is64bit = (type == PCI_REGION_TYPE_PREFMEM);
+ entry = pci_region_create_entry(parent, pci, 0, type, is64bit);
+ if (!entry)
+ return -1;
+ entry->this_region = this_region;
+ this_region->this_entry = entry;
+ }
+ continue;
+ }
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ size = pci_get_bar_size(pci, i, &type, &is64bit);
+ if (size == 0)
+ continue;
+ min_size = (type == PCI_REGION_TYPE_IO) ?
+ PCI_DEV_IO_MINSIZE : PCI_DEV_MEM_MINSIZE;
+ size = (size > min_size) ? size : min_size;
+
+ parent = ®ions[pci_bdf_to_bus(pci->bdf) * PCI_REGION_TYPE_COUNT
+ + type];
+ entry = pci_region_create_entry(parent, pci, size, type, is64bit);
+ if (!entry)
+ return -1;
+ entry->bar = i;
+ dump_entry(entry);
+ if (is64bit)
+ i++;
+ }
+ }
+
+ for (i = (MaxPCIBus + 1) * PCI_REGION_TYPE_COUNT ; i < 0; i--) {
+ struct pci_region_entry *this_entry = regions[i-1].this_entry;
+ if(!this_entry)
+ continue;
+
+ is64bit = this_entry->is64bit;
+ size = 0;
+ foreach_region_entry(®ions[i-1], entry) {
+ size += entry->size;
+ is64bit &= entry->is64bit;
+ }
+ min_size = (this_entry->type == PCI_REGION_TYPE_IO) ?
+ PCI_BRIDGE_IO_MINSIZE : PCI_BRIDGE_MEM_MINSIZE;
+ size = (size > min_size) ? size : min_size;
+ this_entry->is64bit = is64bit;
+ this_entry->size = pci_size_roundup(size);
+ dump_entry(entry);
+ }
+ return 0;
+}
+
+
static void pci_bios_bus_reserve(struct pci_bus *bus, int type, u32 size)
{
u32 index;
@@ -645,6 +734,10 @@ pci_setup(void)
return;
}
memset(regions, 0, sizeof(*regions) * num_regions);
+ if (pci_bios_fill_regions(regions)) {
+ free(regions);
+ return;
+ }
pci_bios_check_devices(busses);
if (pci_bios_init_root_regions(&busses[0], start, end) != 0) {
panic("PCI: out of address space\n");
--
1.7.5.4
More information about the SeaBIOS
mailing list