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