aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlexey Korolev <alexey.korolev@endace.com>2012-04-26 16:51:05 +1200
committerKevin O'Connor <kevin@koconnor.net>2012-04-26 21:52:30 -0400
commit37c111f253c0cad9601e1bb5beb58df50f49f24f (patch)
tree008fd55e9fc57bee50695a6216da4c794a402b8d /src
parentac0cd588edcd63f449b758caf2ff7bef15b4f9f8 (diff)
downloadseabios-37c111f253c0cad9601e1bb5beb58df50f49f24f.tar.gz
pciinit: Calculate pci region stats on demand
Do not store pci region stats - instead calulate the sum and alignment on demand. Signed-off-by: Alexey Korolev <alexey.korolev@endace.com>
Diffstat (limited to 'src')
-rw-r--r--src/pciinit.c60
1 files changed, 38 insertions, 22 deletions
diff --git a/src/pciinit.c b/src/pciinit.c
index 0d66dbea..3b801c68 100644
--- a/src/pciinit.c
+++ b/src/pciinit.c
@@ -40,8 +40,6 @@ struct pci_region_entry {
};
struct pci_region {
- /* pci region stats */
- u64 sum, align;
/* pci region assignments */
u64 base;
struct pci_region_entry *list;
@@ -369,6 +367,25 @@ static int pci_bios_bridge_region_is64(struct pci_region *r,
return 1;
}
+static u64 pci_region_align(struct pci_region *r)
+{
+ if (!r->list)
+ return 1;
+ // The first entry in the sorted list has the largest alignment
+ return r->list->align;
+}
+
+static u64 pci_region_sum(struct pci_region *r)
+{
+ struct pci_region_entry *entry = r->list;
+ u64 sum = 0;
+ while (entry) {
+ sum += entry->size;
+ entry = entry->next;
+ }
+ return sum;
+}
+
static struct pci_region_entry *
pci_region_create_entry(struct pci_bus *bus, struct pci_device *dev,
int bar, u64 size, u64 align, int type, int is64)
@@ -394,10 +411,6 @@ pci_region_create_entry(struct pci_bus *bus, struct pci_device *dev,
}
entry->next = *pprev;
*pprev = entry;
-
- bus->r[type].sum += size;
- if (bus->r[type].align < align)
- bus->r[type].align = align;
return entry;
}
@@ -446,9 +459,10 @@ static int pci_bios_check_devices(struct pci_bus *busses)
for (type = 0; type < PCI_REGION_TYPE_COUNT; type++) {
u64 align = (type == PCI_REGION_TYPE_IO) ?
PCI_BRIDGE_IO_MIN : PCI_BRIDGE_MEM_MIN;
- if (s->r[type].align > align)
- align = s->r[type].align;
- u64 size = ALIGN(s->r[type].sum, align);
+ if (pci_region_align(&s->r[type]) > align)
+ align = pci_region_align(&s->r[type]);
+ u64 sum = pci_region_sum(&s->r[type]);
+ u64 size = ALIGN(sum, align);
int is64 = pci_bios_bridge_region_is64(&s->r[type],
s->bus_dev, type);
// entry->bar is -1 if the entry represents a bridge region
@@ -464,26 +478,28 @@ static int pci_bios_check_devices(struct pci_bus *busses)
return 0;
}
-#define ROOT_BASE(top, sum, align) ALIGN_DOWN((top)-(sum),(align) ?: 1)
-
// Setup region bases (given the regions' size and alignment)
static void pci_bios_init_root_regions(struct pci_bus *bus)
{
- u64 start = BUILD_PCIMEM_START;
- u64 end = BUILD_PCIMEM_END;
-
bus->r[PCI_REGION_TYPE_IO].base = 0xc000;
- int reg1 = PCI_REGION_TYPE_PREFMEM, reg2 = PCI_REGION_TYPE_MEM;
- if (bus->r[reg1].align < bus->r[reg2].align) {
+ struct pci_region *r_end = &bus->r[PCI_REGION_TYPE_PREFMEM];
+ struct pci_region *r_start = &bus->r[PCI_REGION_TYPE_MEM];
+
+ if (pci_region_align(r_start) < pci_region_align(r_end)) {
// Swap regions to improve alignment.
- reg1 = PCI_REGION_TYPE_MEM;
- reg2 = PCI_REGION_TYPE_PREFMEM;
+ r_end = r_start;
+ r_start = &bus->r[PCI_REGION_TYPE_PREFMEM];
}
- bus->r[reg2].base = ROOT_BASE(end, bus->r[reg2].sum, bus->r[reg2].align);
- bus->r[reg1].base = ROOT_BASE(bus->r[reg2].base, bus->r[reg1].sum
- , bus->r[reg1].align);
- if (bus->r[reg1].base < start)
+ u64 sum = pci_region_sum(r_end);
+ u64 align = pci_region_align(r_end);
+ r_end->base = ALIGN_DOWN((BUILD_PCIMEM_END - sum), align);
+ sum = pci_region_sum(r_start);
+ align = pci_region_align(r_start);
+ r_start->base = ALIGN_DOWN((r_end->base - sum), align);
+
+ if ((r_start->base < BUILD_PCIMEM_START) ||
+ (r_start->base > BUILD_PCIMEM_END))
// Memory range requested is larger than available.
panic("PCI: out of address space\n");
}