diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index 33d2ed0fc..d9783da0a 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c @@ -1147,10 +1147,49 @@ PRIVATE void complete_bridges() *===========================================================================*/ PRIVATE void complete_bars() { - int i, j, bar_nr, reg; - u32_t mem_top, io_bottom, io_top, io_high, base, size, v32; + int i, j, r, bar_nr, reg; + u32_t memgap_low, memgap_high, iogap_low, iogap_high, io_high, + base, size, v32, diff1, diff2; + char *cp, *next; + char memstr[256]; - mem_top= 0xfe000000; /* Leave space for the CPU (APIC) */ + r= env_get_param("memory", memstr, sizeof(memstr)); + if (r != OK) + panic("pci", "env_get_param failed", r); + + /* Set memgap_low to just above physical memory */ + memgap_low= 0; + cp= memstr; + while (*cp != '\0') + { + base= strtoul(cp, &next, 16); + if (next == cp || *next != ':') + { + printf("pci: bad memory environment string '%s'\n", + memstr); + panic(NULL, NULL, NO_NUM); + } + cp= next+1; + size= strtoul(cp, &next, 16); + if (next == cp || (*next != ',' && *next != '\0')) + { + printf("pci: bad memory environment string '%s'\n", + memstr); + panic(NULL, NULL, NO_NUM); + } + cp= next+1; + + if (base+size > memgap_low) + memgap_low= base+size; + } + + memgap_high= 0xfe000000; /* Leave space for the CPU (APIC) */ + + if (debug) + { + printf("complete_bars: initial gap: [0x%x .. 0x%x>\n", + memgap_low, memgap_high); + } /* Find the lowest memory base */ for (i= 0; i= memgap_high) + continue; /* Not in the gap */ + if (base+size <= memgap_low) + continue; /* Not in the gap */ + + /* Reduce the gap by the smallest amount */ + diff1= base+size-memgap_low; + diff2= memgap_high-base; + + if (diff1 < diff2) + memgap_low= base+size; + else + memgap_high= base; } } - /* Should check main memory size */ - if (mem_top < 0x80000000) - panic("pci", "mem_top too low", mem_top); + if (debug) + { + printf("complete_bars: intermediate gap: [0x%x .. 0x%x>\n", + memgap_low, memgap_high); + } - io_top= 0x10000; - io_bottom= 0x400; + /* Should check main memory size */ + if (memgap_high < memgap_low) + { + printf("pci: bad memory gap: [0x%x .. 0x%x>\n", + memgap_low, memgap_high); + panic(NULL, NULL, NO_NUM); + } + + iogap_high= 0x10000; + iogap_low= 0x400; /* Find the free I/O space */ for (i= 0; i= io_top) + if (base >= iogap_high) continue; - if (base+size <= io_bottom) + if (base+size <= iogap_low) continue; - if (base+size-io_bottom < io_top-base) - io_bottom= base+size; + if (base+size-iogap_low < iogap_high-base) + iogap_low= base+size; else - io_top= base; + iogap_high= base; } } - if (io_top < io_bottom) - panic("pci", "io_top too low", io_top); + if (iogap_high < iogap_low) + panic("pci", "iogap_high too low", iogap_high); if (debug) - printf("I/O range = [0x%x..0x%x>\n", io_bottom, io_top); + printf("I/O range = [0x%x..0x%x>\n", iogap_low, iogap_high); for (i= 0; i