diff options
Diffstat (limited to 'arch')
-rw-r--r-- | arch/mips/kernel/setup.c | 135 |
1 files changed, 57 insertions, 78 deletions
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 8c2b596a136f..bcbd926e58f7 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c | |||
@@ -96,6 +96,12 @@ void __init add_memory_region(phys_t start, phys_t size, long type) | |||
96 | int x = boot_mem_map.nr_map; | 96 | int x = boot_mem_map.nr_map; |
97 | struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1; | 97 | struct boot_mem_map_entry *prev = boot_mem_map.map + x - 1; |
98 | 98 | ||
99 | /* Sanity check */ | ||
100 | if (start + size < start) { | ||
101 | printk("Trying to add an invalid memory region, skipped\n"); | ||
102 | return; | ||
103 | } | ||
104 | |||
99 | /* | 105 | /* |
100 | * Try to merge with previous entry if any. This is far less than | 106 | * Try to merge with previous entry if any. This is far less than |
101 | * perfect but is sufficient for most real world cases. | 107 | * perfect but is sufficient for most real world cases. |
@@ -257,15 +263,16 @@ static inline int parse_rd_cmdline(unsigned long* rd_start, unsigned long* rd_en | |||
257 | return 0; | 263 | return 0; |
258 | } | 264 | } |
259 | 265 | ||
260 | #define MAXMEM HIGHMEM_START | 266 | /* |
261 | #define MAXMEM_PFN PFN_DOWN(MAXMEM) | 267 | * Initialize the bootmem allocator. It also setup initrd related data |
262 | 268 | * if needed. | |
263 | static inline void bootmem_init(void) | 269 | */ |
270 | static void __init bootmem_init(void) | ||
264 | { | 271 | { |
265 | unsigned long start_pfn; | ||
266 | unsigned long reserved_end = (unsigned long)&_end; | 272 | unsigned long reserved_end = (unsigned long)&_end; |
267 | #ifndef CONFIG_SGI_IP27 | 273 | #ifndef CONFIG_SGI_IP27 |
268 | unsigned long first_usable_pfn; | 274 | unsigned long highest = 0; |
275 | unsigned long mapstart = -1UL; | ||
269 | unsigned long bootmap_size; | 276 | unsigned long bootmap_size; |
270 | int i; | 277 | int i; |
271 | #endif | 278 | #endif |
@@ -281,7 +288,7 @@ static inline void bootmem_init(void) | |||
281 | unsigned long tmp; | 288 | unsigned long tmp; |
282 | u32 *initrd_header; | 289 | u32 *initrd_header; |
283 | 290 | ||
284 | tmp = ((reserved_end + PAGE_SIZE-1) & PAGE_MASK) - sizeof(u32) * 2; | 291 | tmp = PAGE_ALIGN(reserved_end) - sizeof(u32) * 2; |
285 | if (tmp < reserved_end) | 292 | if (tmp < reserved_end) |
286 | tmp += PAGE_SIZE; | 293 | tmp += PAGE_SIZE; |
287 | initrd_header = (u32 *)tmp; | 294 | initrd_header = (u32 *)tmp; |
@@ -294,16 +301,15 @@ static inline void bootmem_init(void) | |||
294 | } | 301 | } |
295 | #endif /* CONFIG_BLK_DEV_INITRD */ | 302 | #endif /* CONFIG_BLK_DEV_INITRD */ |
296 | 303 | ||
304 | #ifndef CONFIG_SGI_IP27 | ||
297 | /* | 305 | /* |
298 | * Partially used pages are not usable - thus | 306 | * reserved_end is now a pfn |
299 | * we are rounding upwards. | ||
300 | */ | 307 | */ |
301 | start_pfn = PFN_UP(CPHYSADDR(reserved_end)); | 308 | reserved_end = PFN_UP(CPHYSADDR(reserved_end)); |
302 | 309 | ||
303 | #ifndef CONFIG_SGI_IP27 | 310 | /* |
304 | /* Find the highest page frame number we have available. */ | 311 | * Find the highest page frame number we have available. |
305 | max_pfn = 0; | 312 | */ |
306 | first_usable_pfn = -1UL; | ||
307 | for (i = 0; i < boot_mem_map.nr_map; i++) { | 313 | for (i = 0; i < boot_mem_map.nr_map; i++) { |
308 | unsigned long start, end; | 314 | unsigned long start, end; |
309 | 315 | ||
@@ -312,56 +318,38 @@ static inline void bootmem_init(void) | |||
312 | 318 | ||
313 | start = PFN_UP(boot_mem_map.map[i].addr); | 319 | start = PFN_UP(boot_mem_map.map[i].addr); |
314 | end = PFN_DOWN(boot_mem_map.map[i].addr | 320 | end = PFN_DOWN(boot_mem_map.map[i].addr |
315 | + boot_mem_map.map[i].size); | 321 | + boot_mem_map.map[i].size); |
316 | 322 | ||
317 | if (start >= end) | 323 | if (end > highest) |
324 | highest = end; | ||
325 | if (end <= reserved_end) | ||
318 | continue; | 326 | continue; |
319 | if (end > max_pfn) | 327 | if (start >= mapstart) |
320 | max_pfn = end; | 328 | continue; |
321 | if (start < first_usable_pfn) { | 329 | mapstart = max(reserved_end, start); |
322 | if (start > start_pfn) { | ||
323 | first_usable_pfn = start; | ||
324 | } else if (end > start_pfn) { | ||
325 | first_usable_pfn = start_pfn; | ||
326 | } | ||
327 | } | ||
328 | } | 330 | } |
329 | 331 | ||
330 | /* | 332 | /* |
331 | * Determine low and high memory ranges | 333 | * Determine low and high memory ranges |
332 | */ | 334 | */ |
333 | max_low_pfn = max_pfn; | 335 | if (highest > PFN_DOWN(HIGHMEM_START)) { |
334 | if (max_low_pfn > MAXMEM_PFN) { | 336 | #ifdef CONFIG_HIGHMEM |
335 | max_low_pfn = MAXMEM_PFN; | 337 | highstart_pfn = PFN_DOWN(HIGHMEM_START); |
336 | #ifndef CONFIG_HIGHMEM | 338 | highend_pfn = highest; |
337 | /* Maximum memory usable is what is directly addressable */ | ||
338 | printk(KERN_WARNING "Warning only %ldMB will be used.\n", | ||
339 | MAXMEM >> 20); | ||
340 | printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); | ||
341 | #endif | 339 | #endif |
340 | highest = PFN_DOWN(HIGHMEM_START); | ||
342 | } | 341 | } |
343 | 342 | ||
344 | #ifdef CONFIG_HIGHMEM | ||
345 | /* | 343 | /* |
346 | * Crude, we really should make a better attempt at detecting | 344 | * Initialize the boot-time allocator with low memory only. |
347 | * highstart_pfn | ||
348 | */ | 345 | */ |
349 | highstart_pfn = highend_pfn = max_pfn; | 346 | bootmap_size = init_bootmem(mapstart, highest); |
350 | if (max_pfn > MAXMEM_PFN) { | ||
351 | highstart_pfn = MAXMEM_PFN; | ||
352 | printk(KERN_NOTICE "%ldMB HIGHMEM available.\n", | ||
353 | (highend_pfn - highstart_pfn) >> (20 - PAGE_SHIFT)); | ||
354 | } | ||
355 | #endif | ||
356 | |||
357 | /* Initialize the boot-time allocator with low memory only. */ | ||
358 | bootmap_size = init_bootmem(first_usable_pfn, max_low_pfn); | ||
359 | 347 | ||
360 | /* | 348 | /* |
361 | * Register fully available low RAM pages with the bootmem allocator. | 349 | * Register fully available low RAM pages with the bootmem allocator. |
362 | */ | 350 | */ |
363 | for (i = 0; i < boot_mem_map.nr_map; i++) { | 351 | for (i = 0; i < boot_mem_map.nr_map; i++) { |
364 | unsigned long curr_pfn, last_pfn, size; | 352 | unsigned long start, end, size; |
365 | 353 | ||
366 | /* | 354 | /* |
367 | * Reserve usable memory. | 355 | * Reserve usable memory. |
@@ -369,49 +357,37 @@ static inline void bootmem_init(void) | |||
369 | if (boot_mem_map.map[i].type != BOOT_MEM_RAM) | 357 | if (boot_mem_map.map[i].type != BOOT_MEM_RAM) |
370 | continue; | 358 | continue; |
371 | 359 | ||
372 | /* | 360 | start = PFN_UP(boot_mem_map.map[i].addr); |
373 | * We are rounding up the start address of usable memory: | 361 | end = PFN_DOWN(boot_mem_map.map[i].addr |
374 | */ | ||
375 | curr_pfn = PFN_UP(boot_mem_map.map[i].addr); | ||
376 | if (curr_pfn >= max_low_pfn) | ||
377 | continue; | ||
378 | if (curr_pfn < start_pfn) | ||
379 | curr_pfn = start_pfn; | ||
380 | |||
381 | /* | ||
382 | * ... and at the end of the usable range downwards: | ||
383 | */ | ||
384 | last_pfn = PFN_DOWN(boot_mem_map.map[i].addr | ||
385 | + boot_mem_map.map[i].size); | 362 | + boot_mem_map.map[i].size); |
386 | |||
387 | if (last_pfn > max_low_pfn) | ||
388 | last_pfn = max_low_pfn; | ||
389 | |||
390 | /* | 363 | /* |
391 | * Only register lowmem part of lowmem segment with bootmem. | 364 | * We are rounding up the start address of usable memory |
365 | * and at the end of the usable range downwards. | ||
392 | */ | 366 | */ |
393 | size = last_pfn - curr_pfn; | 367 | if (start >= max_low_pfn) |
394 | if (curr_pfn > PFN_DOWN(HIGHMEM_START)) | ||
395 | continue; | ||
396 | if (curr_pfn + size - 1 > PFN_DOWN(HIGHMEM_START)) | ||
397 | size = PFN_DOWN(HIGHMEM_START) - curr_pfn; | ||
398 | if (!size) | ||
399 | continue; | 368 | continue; |
369 | if (start < reserved_end) | ||
370 | start = reserved_end; | ||
371 | if (end > max_low_pfn) | ||
372 | end = max_low_pfn; | ||
400 | 373 | ||
401 | /* | 374 | /* |
402 | * ... finally, did all the rounding and playing | 375 | * ... finally, is the area going away? |
403 | * around just make the area go away? | ||
404 | */ | 376 | */ |
405 | if (last_pfn <= curr_pfn) | 377 | if (end <= start) |
406 | continue; | 378 | continue; |
379 | size = end - start; | ||
407 | 380 | ||
408 | /* Register lowmem ranges */ | 381 | /* Register lowmem ranges */ |
409 | free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); | 382 | free_bootmem(PFN_PHYS(start), size << PAGE_SHIFT); |
410 | memory_present(0, curr_pfn, curr_pfn + size - 1); | 383 | memory_present(0, start, end); |
411 | } | 384 | } |
412 | 385 | ||
413 | /* Reserve the bootmap memory. */ | 386 | /* |
414 | reserve_bootmem(PFN_PHYS(first_usable_pfn), bootmap_size); | 387 | * Reserve the bootmap memory. |
388 | */ | ||
389 | reserve_bootmem(PFN_PHYS(mapstart), bootmap_size); | ||
390 | |||
415 | #endif /* CONFIG_SGI_IP27 */ | 391 | #endif /* CONFIG_SGI_IP27 */ |
416 | 392 | ||
417 | #ifdef CONFIG_BLK_DEV_INITRD | 393 | #ifdef CONFIG_BLK_DEV_INITRD |
@@ -483,6 +459,9 @@ static void __init arch_mem_init(char **cmdline_p) | |||
483 | paging_init(); | 459 | paging_init(); |
484 | } | 460 | } |
485 | 461 | ||
462 | #define MAXMEM HIGHMEM_START | ||
463 | #define MAXMEM_PFN PFN_DOWN(MAXMEM) | ||
464 | |||
486 | static inline void resource_init(void) | 465 | static inline void resource_init(void) |
487 | { | 466 | { |
488 | int i; | 467 | int i; |