|
@@ -153,6 +153,35 @@ void __init detect_memory_region(phys_addr_t start, phys_addr_t sz_min, phys_add
|
|
|
add_memory_region(start, size, BOOT_MEM_RAM);
|
|
|
}
|
|
|
|
|
|
+bool __init memory_region_available(phys_addr_t start, phys_addr_t size)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ bool in_ram = false, free = true;
|
|
|
+
|
|
|
+ for (i = 0; i < boot_mem_map.nr_map; i++) {
|
|
|
+ phys_addr_t start_, end_;
|
|
|
+
|
|
|
+ start_ = boot_mem_map.map[i].addr;
|
|
|
+ end_ = boot_mem_map.map[i].addr + boot_mem_map.map[i].size;
|
|
|
+
|
|
|
+ switch (boot_mem_map.map[i].type) {
|
|
|
+ case BOOT_MEM_RAM:
|
|
|
+ if (start >= start_ && start + size <= end_)
|
|
|
+ in_ram = true;
|
|
|
+ break;
|
|
|
+ case BOOT_MEM_RESERVED:
|
|
|
+ if ((start >= start_ && start < end_) ||
|
|
|
+ (start < start_ && start + size >= start_))
|
|
|
+ free = false;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return in_ram && free;
|
|
|
+}
|
|
|
+
|
|
|
static void __init print_memory_map(void)
|
|
|
{
|
|
|
int i;
|
|
@@ -332,11 +361,19 @@ static void __init bootmem_init(void)
|
|
|
|
|
|
#else /* !CONFIG_SGI_IP27 */
|
|
|
|
|
|
+static unsigned long __init bootmap_bytes(unsigned long pages)
|
|
|
+{
|
|
|
+ unsigned long bytes = DIV_ROUND_UP(pages, 8);
|
|
|
+
|
|
|
+ return ALIGN(bytes, sizeof(long));
|
|
|
+}
|
|
|
+
|
|
|
static void __init bootmem_init(void)
|
|
|
{
|
|
|
unsigned long reserved_end;
|
|
|
unsigned long mapstart = ~0UL;
|
|
|
unsigned long bootmap_size;
|
|
|
+ bool bootmap_valid = false;
|
|
|
int i;
|
|
|
|
|
|
/*
|
|
@@ -430,11 +467,42 @@ static void __init bootmem_init(void)
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
|
- * Initialize the boot-time allocator with low memory only.
|
|
|
+ * check that mapstart doesn't overlap with any of
|
|
|
+ * memory regions that have been reserved through eg. DTB
|
|
|
*/
|
|
|
- bootmap_size = init_bootmem_node(NODE_DATA(0), mapstart,
|
|
|
- min_low_pfn, max_low_pfn);
|
|
|
+ bootmap_size = bootmap_bytes(max_low_pfn - min_low_pfn);
|
|
|
+
|
|
|
+ bootmap_valid = memory_region_available(PFN_PHYS(mapstart),
|
|
|
+ bootmap_size);
|
|
|
+ for (i = 0; i < boot_mem_map.nr_map && !bootmap_valid; i++) {
|
|
|
+ unsigned long mapstart_addr;
|
|
|
+
|
|
|
+ switch (boot_mem_map.map[i].type) {
|
|
|
+ case BOOT_MEM_RESERVED:
|
|
|
+ mapstart_addr = PFN_ALIGN(boot_mem_map.map[i].addr +
|
|
|
+ boot_mem_map.map[i].size);
|
|
|
+ if (PHYS_PFN(mapstart_addr) < mapstart)
|
|
|
+ break;
|
|
|
+
|
|
|
+ bootmap_valid = memory_region_available(mapstart_addr,
|
|
|
+ bootmap_size);
|
|
|
+ if (bootmap_valid)
|
|
|
+ mapstart = PHYS_PFN(mapstart_addr);
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
+ if (!bootmap_valid)
|
|
|
+ panic("No memory area to place a bootmap bitmap");
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Initialize the boot-time allocator with low memory only.
|
|
|
+ */
|
|
|
+ if (bootmap_size != init_bootmem_node(NODE_DATA(0), mapstart,
|
|
|
+ min_low_pfn, max_low_pfn))
|
|
|
+ panic("Unexpected memory size required for bootmap");
|
|
|
|
|
|
for (i = 0; i < boot_mem_map.nr_map; i++) {
|
|
|
unsigned long start, end;
|