diff options
author | Ralf Baechle <ralf@linux-mips.org> | 2000-12-11 16:41:05 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 2000-12-11 16:41:05 +0000 |
commit | 97b7ae4257ef7ba8ed9b7944a4f56a49af3e8abb (patch) | |
tree | bf175d9a387ad897d3061b24fa88ac0dfe8ba52b /arch/mips/kernel/setup.c | |
parent | 1bb58fdb51c720e86c239ed5957ecac02d9b0920 (diff) |
Memmap fixes from Maciej.
Diffstat (limited to 'arch/mips/kernel/setup.c')
-rw-r--r-- | arch/mips/kernel/setup.c | 228 |
1 files changed, 220 insertions, 8 deletions
diff --git a/arch/mips/kernel/setup.c b/arch/mips/kernel/setup.c index 1a679e64a..08ceb6758 100644 --- a/arch/mips/kernel/setup.c +++ b/arch/mips/kernel/setup.c @@ -6,6 +6,7 @@ * Copyright (C) 1995 Linus Torvalds * Copyright (C) 1995, 1996, 1997, 1998, 1999, 2000 Ralf Baechle * Copyright (C) 1996 Stoned Elipot + * Copyright (C) 2000 Maciej W. Rozycki */ #include <linux/config.h> #include <linux/errno.h> @@ -99,12 +100,14 @@ unsigned long mips_memory_upper = KSEG0; /* this is set by kernel_entry() */ unsigned long mips_machtype = MACH_UNKNOWN; unsigned long mips_machgroup = MACH_GROUP_UNKNOWN; +struct boot_mem_map boot_mem_map; + unsigned char aux_device_present; -extern int _end; +extern char _ftext, _etext, _fdata, _edata, _end; -static char command_line[CL_SIZE] = { 0, }; - char saved_command_line[CL_SIZE]; -extern char arcs_cmdline[CL_SIZE]; +static char command_line[COMMAND_LINE_SIZE]; + char saved_command_line[COMMAND_LINE_SIZE]; +extern char arcs_cmdline[COMMAND_LINE_SIZE]; /* * The board specific setup routine sets irq_setup to point to a board @@ -130,6 +133,9 @@ extern void loadmmu(void); extern asmlinkage void start_kernel(void); extern int prom_init(int, char **, char **, int *); +static struct resource code_resource = { "Kernel code" }; +static struct resource data_resource = { "Kernel data" }; + /* * Probe whether cpu has config register by trying to play with * alternate cache bit and see whether it matters. @@ -341,6 +347,97 @@ static void __init default_irq_setup(void) panic("Unknown machtype in init_IRQ"); } +void __init add_memory_region(unsigned long start, unsigned long size, + long type) +{ + int x = boot_mem_map.nr_map; + + if (x == BOOT_MEM_MAP_MAX) { + printk("Ooops! Too many entries in the memory map!\n"); + return; + } + + boot_mem_map.map[x].addr = start; + boot_mem_map.map[x].size = size; + boot_mem_map.map[x].type = type; + boot_mem_map.nr_map++; +} + +static void __init print_memory_map(void) +{ + int i; + + for (i = 0; i < boot_mem_map.nr_map; i++) { + printk(" memory: %08lx @ %08lx ", + boot_mem_map.map[i].size, boot_mem_map.map[i].addr); + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + printk("(usable)\n"); + break; + case BOOT_MEM_ROM_DATA: + printk("(ROM data)\n"); + break; + case BOOT_MEM_RESERVED: + printk("(reserved)\n"); + break; + default: + printk("type %lu\n", boot_mem_map.map[i].type); + break; + } + } +} + +static inline void parse_mem_cmdline(void) +{ + char c = ' ', *to = command_line, *from = saved_command_line; + unsigned long start_at, mem_size; + int len = 0; + int usermem = 0; + + printk("Determined physical RAM map:\n"); + print_memory_map(); + + for (;;) { + /* + * "mem=XXX[kKmM]" defines a memory region from + * 0 to <XXX>, overriding the determined size. + * "mem=XXX[KkmM]@YYY[KkmM]" defines a memory region from + * <YYY> to <YYY>+<XXX>, overriding the determined size. + */ + if (c == ' ' && !memcmp(from, "mem=", 4)) { + if (to != command_line) + to--; + /* + * If a user specifies memory size, we + * blow away any automatically generated + * size. + */ + if (usermem == 0) { + boot_mem_map.nr_map = 0; + usermem = 1; + } + mem_size = memparse(from + 4, &from); + if (*from == '@') + start_at = memparse(from + 1, &from); + else + start_at = 0; + add_memory_region(start_at, mem_size, BOOT_MEM_RAM); + } + c = *(from++); + if (!c) + break; + if (COMMAND_LINE_SIZE <= ++len) + break; + *(to++) = c; + } + *to = '\0'; + + if (usermem) { + printk("User-defined physical RAM map:\n"); + print_memory_map(); + } +} + void __init setup_arch(char **cmdline_p) { void baget_setup(void); @@ -355,6 +452,10 @@ void __init setup_arch(char **cmdline_p) void atlas_setup(void); void malta_setup(void); + unsigned long bootmap_size; + unsigned long start_pfn, max_pfn; + int i; + /* Save defaults for configuration-dependent routines. */ irq_setup = default_irq_setup; @@ -434,12 +535,88 @@ void __init setup_arch(char **cmdline_p) panic("Unsupported architecture"); } - strncpy (command_line, arcs_cmdline, CL_SIZE); - memcpy(saved_command_line, command_line, CL_SIZE); - saved_command_line[CL_SIZE-1] = '\0'; - + strncpy(command_line, arcs_cmdline, sizeof command_line); + command_line[sizeof command_line - 1] = 0; + strcpy(saved_command_line, command_line); *cmdline_p = command_line; + parse_mem_cmdline(); + +#define PFN_UP(x) (((x) + PAGE_SIZE - 1) >> PAGE_SHIFT) +#define PFN_DOWN(x) ((x) >> PAGE_SHIFT) +#define PFN_PHYS(x) ((x) << PAGE_SHIFT) + + /* + * Partially used pages are not usable - thus + * we are rounding upwards. + */ + start_pfn = PFN_UP(__pa(&_end)); + + /* Find the highest page frame number we have available. */ + max_pfn = 0; + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long start, end; + + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + start = PFN_UP(boot_mem_map.map[i].addr); + end = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (start >= end) + continue; + if (end > max_pfn) + max_pfn = end; + } + + /* Initialize the boot-time allocator. */ + bootmap_size = init_bootmem(start_pfn, max_pfn); + + /* + * Register fully available low RAM pages with the bootmem allocator. + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + unsigned long curr_pfn, last_pfn, size; + + /* + * Reserve usable memory. + */ + if (boot_mem_map.map[i].type != BOOT_MEM_RAM) + continue; + + /* + * We are rounding up the start address of usable memory: + */ + curr_pfn = PFN_UP(boot_mem_map.map[i].addr); + if (curr_pfn >= max_pfn) + continue; + if (curr_pfn < start_pfn) + curr_pfn = start_pfn; + + /* + * ... and at the end of the usable range downwards: + */ + last_pfn = PFN_DOWN(boot_mem_map.map[i].addr + + boot_mem_map.map[i].size); + + if (last_pfn > max_pfn) + last_pfn = max_pfn; + + /* + * ... finally, did all the rounding and playing + * around just make the area go away? + */ + if (last_pfn <= curr_pfn) + continue; + + size = last_pfn - curr_pfn; + free_bootmem(PFN_PHYS(curr_pfn), PFN_PHYS(size)); + } + + /* Reserve the bootmap memory. */ + reserve_bootmem(PFN_PHYS(start_pfn), bootmap_size); + #if 0 #ifdef CONFIG_BLK_DEV_INITRD #error "Fixme, I'm broken." @@ -463,6 +640,41 @@ void __init setup_arch(char **cmdline_p) #endif /* 0 */ paging_init(); + + code_resource.start = virt_to_bus(&_ftext); + code_resource.end = virt_to_bus(&_etext) - 1; + data_resource.start = virt_to_bus(&_fdata); + data_resource.end = virt_to_bus(&_edata) - 1; + + /* + * Request address space for all standard RAM. + */ + for (i = 0; i < boot_mem_map.nr_map; i++) { + struct resource *res; + + res = alloc_bootmem(sizeof(struct resource)); + switch (boot_mem_map.map[i].type) { + case BOOT_MEM_RAM: + case BOOT_MEM_ROM_DATA: + res->name = "System RAM"; + break; + case BOOT_MEM_RESERVED: + default: + res->name = "reserved"; + } + res->start = boot_mem_map.map[i].addr; + res->end = res->start + boot_mem_map.map[i].size - 1; + res->flags = IORESOURCE_MEM | IORESOURCE_BUSY; + request_resource(&iomem_resource, res); + + /* + * We dont't know which RAM region contains kernel data, + * so we try it repeatedly and let the resource manager + * test it. + */ + request_resource(res, &code_resource); + request_resource(res, &data_resource); + } } void r3081_wait(void) |