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