diff options
Diffstat (limited to 'arch/avr32/kernel')
-rw-r--r-- | arch/avr32/kernel/setup.c | 238 |
1 files changed, 238 insertions, 0 deletions
diff --git a/arch/avr32/kernel/setup.c b/arch/avr32/kernel/setup.c index a1a7c3c3f522..53a1ff0cb05c 100644 --- a/arch/avr32/kernel/setup.c +++ b/arch/avr32/kernel/setup.c | |||
@@ -8,12 +8,14 @@ | |||
8 | 8 | ||
9 | #include <linux/clk.h> | 9 | #include <linux/clk.h> |
10 | #include <linux/init.h> | 10 | #include <linux/init.h> |
11 | #include <linux/initrd.h> | ||
11 | #include <linux/sched.h> | 12 | #include <linux/sched.h> |
12 | #include <linux/console.h> | 13 | #include <linux/console.h> |
13 | #include <linux/ioport.h> | 14 | #include <linux/ioport.h> |
14 | #include <linux/bootmem.h> | 15 | #include <linux/bootmem.h> |
15 | #include <linux/fs.h> | 16 | #include <linux/fs.h> |
16 | #include <linux/module.h> | 17 | #include <linux/module.h> |
18 | #include <linux/pfn.h> | ||
17 | #include <linux/root_dev.h> | 19 | #include <linux/root_dev.h> |
18 | #include <linux/cpu.h> | 20 | #include <linux/cpu.h> |
19 | #include <linux/kernel.h> | 21 | #include <linux/kernel.h> |
@@ -260,6 +262,242 @@ static void __init parse_tags(struct tag *t) | |||
260 | t->hdr.tag); | 262 | t->hdr.tag); |
261 | } | 263 | } |
262 | 264 | ||
265 | static void __init print_memory_map(const char *what, | ||
266 | struct tag_mem_range *mem) | ||
267 | { | ||
268 | printk ("%s:\n", what); | ||
269 | for (; mem; mem = mem->next) { | ||
270 | printk (" %08lx - %08lx\n", | ||
271 | (unsigned long)mem->addr, | ||
272 | (unsigned long)(mem->addr + mem->size)); | ||
273 | } | ||
274 | } | ||
275 | |||
276 | #define MAX_LOWMEM HIGHMEM_START | ||
277 | #define MAX_LOWMEM_PFN PFN_DOWN(MAX_LOWMEM) | ||
278 | |||
279 | /* | ||
280 | * Sort a list of memory regions in-place by ascending address. | ||
281 | * | ||
282 | * We're using bubble sort because we only have singly linked lists | ||
283 | * with few elements. | ||
284 | */ | ||
285 | static void __init sort_mem_list(struct tag_mem_range **pmem) | ||
286 | { | ||
287 | int done; | ||
288 | struct tag_mem_range **a, **b; | ||
289 | |||
290 | if (!*pmem) | ||
291 | return; | ||
292 | |||
293 | do { | ||
294 | done = 1; | ||
295 | a = pmem, b = &(*pmem)->next; | ||
296 | while (*b) { | ||
297 | if ((*a)->addr > (*b)->addr) { | ||
298 | struct tag_mem_range *tmp; | ||
299 | tmp = (*b)->next; | ||
300 | (*b)->next = *a; | ||
301 | *a = *b; | ||
302 | *b = tmp; | ||
303 | done = 0; | ||
304 | } | ||
305 | a = &(*a)->next; | ||
306 | b = &(*a)->next; | ||
307 | } | ||
308 | } while (!done); | ||
309 | } | ||
310 | |||
311 | /* | ||
312 | * Find a free memory region large enough for storing the | ||
313 | * bootmem bitmap. | ||
314 | */ | ||
315 | static unsigned long __init | ||
316 | find_bootmap_pfn(const struct tag_mem_range *mem) | ||
317 | { | ||
318 | unsigned long bootmap_pages, bootmap_len; | ||
319 | unsigned long node_pages = PFN_UP(mem->size); | ||
320 | unsigned long bootmap_addr = mem->addr; | ||
321 | struct tag_mem_range *reserved = mem_reserved; | ||
322 | struct tag_mem_range *ramdisk = mem_ramdisk; | ||
323 | unsigned long kern_start = __pa(_stext); | ||
324 | unsigned long kern_end = __pa(_end); | ||
325 | |||
326 | bootmap_pages = bootmem_bootmap_pages(node_pages); | ||
327 | bootmap_len = bootmap_pages << PAGE_SHIFT; | ||
328 | |||
329 | /* | ||
330 | * Find a large enough region without reserved pages for | ||
331 | * storing the bootmem bitmap. We can take advantage of the | ||
332 | * fact that all lists have been sorted. | ||
333 | * | ||
334 | * We have to check explicitly reserved regions as well as the | ||
335 | * kernel image and any RAMDISK images... | ||
336 | * | ||
337 | * Oh, and we have to make sure we don't overwrite the taglist | ||
338 | * since we're going to use it until the bootmem allocator is | ||
339 | * fully up and running. | ||
340 | */ | ||
341 | while (1) { | ||
342 | if ((bootmap_addr < kern_end) && | ||
343 | ((bootmap_addr + bootmap_len) > kern_start)) | ||
344 | bootmap_addr = kern_end; | ||
345 | |||
346 | while (reserved && | ||
347 | (bootmap_addr >= (reserved->addr + reserved->size))) | ||
348 | reserved = reserved->next; | ||
349 | |||
350 | if (reserved && | ||
351 | ((bootmap_addr + bootmap_len) >= reserved->addr)) { | ||
352 | bootmap_addr = reserved->addr + reserved->size; | ||
353 | continue; | ||
354 | } | ||
355 | |||
356 | while (ramdisk && | ||
357 | (bootmap_addr >= (ramdisk->addr + ramdisk->size))) | ||
358 | ramdisk = ramdisk->next; | ||
359 | |||
360 | if (!ramdisk || | ||
361 | ((bootmap_addr + bootmap_len) < ramdisk->addr)) | ||
362 | break; | ||
363 | |||
364 | bootmap_addr = ramdisk->addr + ramdisk->size; | ||
365 | } | ||
366 | |||
367 | if ((PFN_UP(bootmap_addr) + bootmap_len) >= (mem->addr + mem->size)) | ||
368 | return ~0UL; | ||
369 | |||
370 | return PFN_UP(bootmap_addr); | ||
371 | } | ||
372 | |||
373 | static void __init setup_bootmem(void) | ||
374 | { | ||
375 | unsigned bootmap_size; | ||
376 | unsigned long first_pfn, bootmap_pfn, pages; | ||
377 | unsigned long max_pfn, max_low_pfn; | ||
378 | unsigned long kern_start = __pa(_stext); | ||
379 | unsigned long kern_end = __pa(_end); | ||
380 | unsigned node = 0; | ||
381 | struct tag_mem_range *bank, *res; | ||
382 | |||
383 | sort_mem_list(&mem_phys); | ||
384 | sort_mem_list(&mem_reserved); | ||
385 | |||
386 | print_memory_map("Physical memory", mem_phys); | ||
387 | print_memory_map("Reserved memory", mem_reserved); | ||
388 | |||
389 | nodes_clear(node_online_map); | ||
390 | |||
391 | if (mem_ramdisk) { | ||
392 | #ifdef CONFIG_BLK_DEV_INITRD | ||
393 | initrd_start = (unsigned long)__va(mem_ramdisk->addr); | ||
394 | initrd_end = initrd_start + mem_ramdisk->size; | ||
395 | |||
396 | print_memory_map("RAMDISK images", mem_ramdisk); | ||
397 | if (mem_ramdisk->next) | ||
398 | printk(KERN_WARNING | ||
399 | "Warning: Only the first RAMDISK image " | ||
400 | "will be used\n"); | ||
401 | sort_mem_list(&mem_ramdisk); | ||
402 | #else | ||
403 | printk(KERN_WARNING "RAM disk image present, but " | ||
404 | "no initrd support in kernel!\n"); | ||
405 | #endif | ||
406 | } | ||
407 | |||
408 | if (mem_phys->next) | ||
409 | printk(KERN_WARNING "Only using first memory bank\n"); | ||
410 | |||
411 | for (bank = mem_phys; bank; bank = NULL) { | ||
412 | first_pfn = PFN_UP(bank->addr); | ||
413 | max_low_pfn = max_pfn = PFN_DOWN(bank->addr + bank->size); | ||
414 | bootmap_pfn = find_bootmap_pfn(bank); | ||
415 | if (bootmap_pfn > max_pfn) | ||
416 | panic("No space for bootmem bitmap!\n"); | ||
417 | |||
418 | if (max_low_pfn > MAX_LOWMEM_PFN) { | ||
419 | max_low_pfn = MAX_LOWMEM_PFN; | ||
420 | #ifndef CONFIG_HIGHMEM | ||
421 | /* | ||
422 | * Lowmem is memory that can be addressed | ||
423 | * directly through P1/P2 | ||
424 | */ | ||
425 | printk(KERN_WARNING | ||
426 | "Node %u: Only %ld MiB of memory will be used.\n", | ||
427 | node, MAX_LOWMEM >> 20); | ||
428 | printk(KERN_WARNING "Use a HIGHMEM enabled kernel.\n"); | ||
429 | #else | ||
430 | #error HIGHMEM is not supported by AVR32 yet | ||
431 | #endif | ||
432 | } | ||
433 | |||
434 | /* Initialize the boot-time allocator with low memory only. */ | ||
435 | bootmap_size = init_bootmem_node(NODE_DATA(node), bootmap_pfn, | ||
436 | first_pfn, max_low_pfn); | ||
437 | |||
438 | printk("Node %u: bdata = %p, bdata->node_bootmem_map = %p\n", | ||
439 | node, NODE_DATA(node)->bdata, | ||
440 | NODE_DATA(node)->bdata->node_bootmem_map); | ||
441 | |||
442 | /* | ||
443 | * Register fully available RAM pages with the bootmem | ||
444 | * allocator. | ||
445 | */ | ||
446 | pages = max_low_pfn - first_pfn; | ||
447 | free_bootmem_node (NODE_DATA(node), PFN_PHYS(first_pfn), | ||
448 | PFN_PHYS(pages)); | ||
449 | |||
450 | /* | ||
451 | * Reserve space for the kernel image (if present in | ||
452 | * this node)... | ||
453 | */ | ||
454 | if ((kern_start >= PFN_PHYS(first_pfn)) && | ||
455 | (kern_start < PFN_PHYS(max_pfn))) { | ||
456 | printk("Node %u: Kernel image %08lx - %08lx\n", | ||
457 | node, kern_start, kern_end); | ||
458 | reserve_bootmem_node(NODE_DATA(node), kern_start, | ||
459 | kern_end - kern_start); | ||
460 | } | ||
461 | |||
462 | /* ...the bootmem bitmap... */ | ||
463 | reserve_bootmem_node(NODE_DATA(node), | ||
464 | PFN_PHYS(bootmap_pfn), | ||
465 | bootmap_size); | ||
466 | |||
467 | /* ...any RAMDISK images... */ | ||
468 | for (res = mem_ramdisk; res; res = res->next) { | ||
469 | if (res->addr > PFN_PHYS(max_pfn)) | ||
470 | break; | ||
471 | |||
472 | if (res->addr >= PFN_PHYS(first_pfn)) { | ||
473 | printk("Node %u: RAMDISK %08lx - %08lx\n", | ||
474 | node, | ||
475 | (unsigned long)res->addr, | ||
476 | (unsigned long)(res->addr + res->size)); | ||
477 | reserve_bootmem_node(NODE_DATA(node), | ||
478 | res->addr, res->size); | ||
479 | } | ||
480 | } | ||
481 | |||
482 | /* ...and any other reserved regions. */ | ||
483 | for (res = mem_reserved; res; res = res->next) { | ||
484 | if (res->addr > PFN_PHYS(max_pfn)) | ||
485 | break; | ||
486 | |||
487 | if (res->addr >= PFN_PHYS(first_pfn)) { | ||
488 | printk("Node %u: Reserved %08lx - %08lx\n", | ||
489 | node, | ||
490 | (unsigned long)res->addr, | ||
491 | (unsigned long)(res->addr + res->size)); | ||
492 | reserve_bootmem_node(NODE_DATA(node), | ||
493 | res->addr, res->size); | ||
494 | } | ||
495 | } | ||
496 | |||
497 | node_set_online(node); | ||
498 | } | ||
499 | } | ||
500 | |||
263 | void __init setup_arch (char **cmdline_p) | 501 | void __init setup_arch (char **cmdline_p) |
264 | { | 502 | { |
265 | struct clk *cpu_clk; | 503 | struct clk *cpu_clk; |