diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index c879c40aa7a5..f0679be4f96f 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -60,6 +60,8 @@ struct { #define CHUNK_READ_WRITE 0 #define CHUNK_READ_ONLY 1 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ +unsigned long __initdata zholes_size[MAX_NR_ZONES]; +static unsigned long __initdata memory_end; /* * Setup options @@ -78,11 +80,15 @@ static char command_line[COMMAND_LINE_SIZE] = { 0, }; static struct resource code_resource = { .name = "Kernel code", + .start = (unsigned long) &_text, + .end = (unsigned long) &_etext - 1, .flags = IORESOURCE_BUSY | IORESOURCE_MEM, }; static struct resource data_resource = { .name = "Kernel data", + .start = (unsigned long) &_etext, + .end = (unsigned long) &_edata - 1, .flags = IORESOURCE_BUSY | IORESOURCE_MEM, }; @@ -310,90 +316,50 @@ void machine_power_off(void) EXPORT_SYMBOL(machine_power_off); -/* - * Setup function called from init/main.c just after the banner - * was printed. - */ -extern char _pstart, _pend, _stext; - -void __init setup_arch(char **cmdline_p) +static void __init +add_memory_hole(unsigned long start, unsigned long end) { - unsigned long bootmap_size; - unsigned long memory_start, memory_end; - char c = ' ', cn, *to = command_line, *from = COMMAND_LINE; - unsigned long start_pfn, end_pfn; - static unsigned int smptrap=0; - unsigned long delay = 0; - struct _lowcore *lc; - int i; + unsigned long dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT; - if (smptrap) - return; - smptrap=1; + if (end <= dma_pfn) + zholes_size[ZONE_DMA] += end - start + 1; + else if (start > dma_pfn) + zholes_size[ZONE_NORMAL] += end - start + 1; + else { + zholes_size[ZONE_DMA] += dma_pfn - start + 1; + zholes_size[ZONE_NORMAL] += end - dma_pfn; + } +} - /* - * print what head.S has found out about the machine - */ -#ifndef CONFIG_ARCH_S390X - printk((MACHINE_IS_VM) ? - "We are running under VM (31 bit mode)\n" : - "We are running native (31 bit mode)\n"); - printk((MACHINE_HAS_IEEE) ? - "This machine has an IEEE fpu\n" : - "This machine has no IEEE fpu\n"); -#else /* CONFIG_ARCH_S390X */ - printk((MACHINE_IS_VM) ? - "We are running under VM (64 bit mode)\n" : - "We are running native (64 bit mode)\n"); -#endif /* CONFIG_ARCH_S390X */ +static void __init +parse_cmdline_early(char **cmdline_p) +{ + char c = ' ', cn, *to = command_line, *from = COMMAND_LINE; + unsigned long delay = 0; - ROOT_DEV = Root_RAM0; - memory_start = (unsigned long) &_end; /* fixit if use $CODELO etc*/ -#ifndef CONFIG_ARCH_S390X - memory_end = memory_size & ~0x400000UL; /* align memory end to 4MB */ - /* - * We need some free virtual space to be able to do vmalloc. - * On a machine with 2GB memory we make sure that we have at - * least 128 MB free space for vmalloc. - */ - if (memory_end > 1920*1024*1024) - memory_end = 1920*1024*1024; -#else /* CONFIG_ARCH_S390X */ - memory_end = memory_size & ~0x200000UL; /* detected in head.s */ -#endif /* CONFIG_ARCH_S390X */ - init_mm.start_code = PAGE_OFFSET; - init_mm.end_code = (unsigned long) &_etext; - init_mm.end_data = (unsigned long) &_edata; - init_mm.brk = (unsigned long) &_end; + /* Save unparsed command line copy for /proc/cmdline */ + memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); + saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; - code_resource.start = (unsigned long) &_text; - code_resource.end = (unsigned long) &_etext - 1; - data_resource.start = (unsigned long) &_etext; - data_resource.end = (unsigned long) &_edata - 1; - - /* Save unparsed command line copy for /proc/cmdline */ - memcpy(saved_command_line, COMMAND_LINE, COMMAND_LINE_SIZE); - saved_command_line[COMMAND_LINE_SIZE-1] = '\0'; - - for (;;) { - /* - * "mem=XXX[kKmM]" sets memsize - */ - if (c == ' ' && strncmp(from, "mem=", 4) == 0) { - memory_end = simple_strtoul(from+4, &from, 0); - if ( *from == 'K' || *from == 'k' ) { - memory_end = memory_end << 10; - from++; - } else if ( *from == 'M' || *from == 'm' ) { - memory_end = memory_end << 20; - from++; - } - } - /* - * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes - */ - if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) { - delay = simple_strtoul(from+9, &from, 0); + for (;;) { + /* + * "mem=XXX[kKmM]" sets memsize + */ + if (c == ' ' && strncmp(from, "mem=", 4) == 0) { + memory_end = simple_strtoul(from+4, &from, 0); + if ( *from == 'K' || *from == 'k' ) { + memory_end = memory_end << 10; + from++; + } else if ( *from == 'M' || *from == 'm' ) { + memory_end = memory_end << 20; + from++; + } + } + /* + * "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes + */ + if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) { + delay = simple_strtoul(from+9, &from, 0); if (*from == 's' || *from == 'S') { delay = delay*1000000; from++; @@ -403,115 +369,39 @@ void __init setup_arch(char **cmdline_p) } /* now wait for the requested amount of time */ udelay(delay); - } - cn = *(from++); - if (!cn) - break; - if (cn == '\n') - cn = ' '; /* replace newlines with space */ + } + cn = *(from++); + if (!cn) + break; + if (cn == '\n') + cn = ' '; /* replace newlines with space */ if (cn == 0x0d) cn = ' '; /* replace 0x0d with space */ - if (cn == ' ' && c == ' ') - continue; /* remove additional spaces */ - c = cn; - if (to - command_line >= COMMAND_LINE_SIZE) - break; - *(to++) = c; - } - if (c == ' ' && to > command_line) to--; - *to = '\0'; - *cmdline_p = command_line; - - /* - * partially used pages are not usable - thus - * we are rounding upwards: - */ - start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT; - end_pfn = max_pfn = memory_end >> PAGE_SHIFT; - - /* - * Initialize the boot-time allocator (with low memory only): - */ - bootmap_size = init_bootmem(start_pfn, end_pfn); - - /* - * Register RAM areas with the bootmem allocator. - */ - for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) { - unsigned long start_chunk, end_chunk; - - if (memory_chunk[i].type != CHUNK_READ_WRITE) - continue; - start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1); - start_chunk >>= PAGE_SHIFT; - end_chunk = (memory_chunk[i].addr + memory_chunk[i].size); - end_chunk >>= PAGE_SHIFT; - if (start_chunk < start_pfn) - start_chunk = start_pfn; - if (end_chunk > end_pfn) - end_chunk = end_pfn; - if (start_chunk < end_chunk) - free_bootmem(start_chunk << PAGE_SHIFT, - (end_chunk - start_chunk) << PAGE_SHIFT); - } - - /* - * Reserve the bootmem bitmap itself as well. We do this in two - * steps (first step was init_bootmem()) because this catches - * the (very unlikely) case of us accidentally initializing the - * bootmem allocator with an invalid RAM area. - */ - reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); - -#ifdef CONFIG_BLK_DEV_INITRD - if (INITRD_START) { - if (INITRD_START + INITRD_SIZE <= memory_end) { - reserve_bootmem(INITRD_START, INITRD_SIZE); - initrd_start = INITRD_START; - initrd_end = initrd_start + INITRD_SIZE; - } else { - printk("initrd extends beyond end of memory " - "(0x%08lx > 0x%08lx)\ndisabling initrd\n", - initrd_start + INITRD_SIZE, memory_end); - initrd_start = initrd_end = 0; - } - } -#endif - - for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) { - struct resource *res; - - res = alloc_bootmem_low(sizeof(struct resource)); - res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; - - switch (memory_chunk[i].type) { - case CHUNK_READ_WRITE: - res->name = "System RAM"; + if (cn == ' ' && c == ' ') + continue; /* remove additional spaces */ + c = cn; + if (to - command_line >= COMMAND_LINE_SIZE) break; - case CHUNK_READ_ONLY: - res->name = "System ROM"; - res->flags |= IORESOURCE_READONLY; - break; - default: - res->name = "reserved"; - } - res->start = memory_chunk[i].addr; - res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; - request_resource(&iomem_resource, res); - request_resource(res, &code_resource); - request_resource(res, &data_resource); + *(to++) = c; } + if (c == ' ' && to > command_line) to--; + *to = '\0'; + *cmdline_p = command_line; +} - /* - * Setup lowcore for boot cpu - */ -#ifndef CONFIG_ARCH_S390X - lc = (struct _lowcore *) __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0); - memset(lc, 0, PAGE_SIZE); -#else /* CONFIG_ARCH_S390X */ - lc = (struct _lowcore *) __alloc_bootmem(2*PAGE_SIZE, 2*PAGE_SIZE, 0); - memset(lc, 0, 2*PAGE_SIZE); -#endif /* CONFIG_ARCH_S390X */ +static void __init +setup_lowcore(void) +{ + struct _lowcore *lc; + int lc_pages; + + /* + * Setup lowcore for boot cpu + */ + lc_pages = sizeof(void *) == 8 ? 2 : 1; + lc = (struct _lowcore *) + __alloc_bootmem(lc_pages * PAGE_SIZE, lc_pages * PAGE_SIZE, 0); + memset(lc, 0, lc_pages * PAGE_SIZE); lc->restart_psw.mask = PSW_BASE_BITS; lc->restart_psw.addr = PSW_ADDR_AMODE | (unsigned long) restart_int_handler; @@ -546,6 +436,159 @@ void __init setup_arch(char **cmdline_p) lc->diag44_opcode = 0x07000700; #endif /* CONFIG_ARCH_S390X */ set_prefix((u32)(unsigned long) lc); +} + +static void __init +setup_resources(void) +{ + struct resource *res; + int i; + + for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { + res = alloc_bootmem_low(sizeof(struct resource)); + res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; + switch (memory_chunk[i].type) { + case CHUNK_READ_WRITE: + res->name = "System RAM"; + break; + case CHUNK_READ_ONLY: + res->name = "System ROM"; + res->flags |= IORESOURCE_READONLY; + break; + default: + res->name = "reserved"; + } + res->start = memory_chunk[i].addr; + res->end = memory_chunk[i].addr + memory_chunk[i].size - 1; + request_resource(&iomem_resource, res); + request_resource(res, &code_resource); + request_resource(res, &data_resource); + } +} + +static void __init +setup_memory(void) +{ + unsigned long bootmap_size; + unsigned long start_pfn, end_pfn; + unsigned long last_rw_end; + int i; + + /* + * partially used pages are not usable - thus + * we are rounding upwards: + */ + start_pfn = (__pa(&_end) + PAGE_SIZE - 1) >> PAGE_SHIFT; + end_pfn = max_pfn = memory_end >> PAGE_SHIFT; + + /* + * Initialize the boot-time allocator (with low memory only): + */ + bootmap_size = init_bootmem(start_pfn, end_pfn); + + /* + * Register RAM areas with the bootmem allocator. + */ + last_rw_end = start_pfn; + + for (i = 0; i < 16 && memory_chunk[i].size > 0; i++) { + unsigned long start_chunk, end_chunk; + + if (memory_chunk[i].type != CHUNK_READ_WRITE) + continue; + start_chunk = (memory_chunk[i].addr + PAGE_SIZE - 1); + start_chunk >>= PAGE_SHIFT; + end_chunk = (memory_chunk[i].addr + memory_chunk[i].size); + end_chunk >>= PAGE_SHIFT; + if (start_chunk < start_pfn) + start_chunk = start_pfn; + if (end_chunk > end_pfn) + end_chunk = end_pfn; + if (start_chunk < end_chunk) { + free_bootmem(start_chunk << PAGE_SHIFT, + (end_chunk - start_chunk) << PAGE_SHIFT); + if (last_rw_end < start_chunk) + add_memory_hole(last_rw_end, start_chunk - 1); + last_rw_end = end_chunk; + } + } + + if (last_rw_end < end_pfn - 1) + add_memory_hole(last_rw_end, end_pfn - 1); + + /* + * Reserve the bootmem bitmap itself as well. We do this in two + * steps (first step was init_bootmem()) because this catches + * the (very unlikely) case of us accidentally initializing the + * bootmem allocator with an invalid RAM area. + */ + reserve_bootmem(start_pfn << PAGE_SHIFT, bootmap_size); + +#ifdef CONFIG_BLK_DEV_INITRD + if (INITRD_START) { + if (INITRD_START + INITRD_SIZE <= memory_end) { + reserve_bootmem(INITRD_START, INITRD_SIZE); + initrd_start = INITRD_START; + initrd_end = initrd_start + INITRD_SIZE; + } else { + printk("initrd extends beyond end of memory " + "(0x%08lx > 0x%08lx)\ndisabling initrd\n", + initrd_start + INITRD_SIZE, memory_end); + initrd_start = initrd_end = 0; + } + } +#endif +} + +/* + * Setup function called from init/main.c just after the banner + * was printed. + */ + +void __init +setup_arch(char **cmdline_p) +{ + /* + * print what head.S has found out about the machine + */ +#ifndef CONFIG_ARCH_S390X + printk((MACHINE_IS_VM) ? + "We are running under VM (31 bit mode)\n" : + "We are running native (31 bit mode)\n"); + printk((MACHINE_HAS_IEEE) ? + "This machine has an IEEE fpu\n" : + "This machine has no IEEE fpu\n"); +#else /* CONFIG_ARCH_S390X */ + printk((MACHINE_IS_VM) ? + "We are running under VM (64 bit mode)\n" : + "We are running native (64 bit mode)\n"); +#endif /* CONFIG_ARCH_S390X */ + + ROOT_DEV = Root_RAM0; +#ifndef CONFIG_ARCH_S390X + memory_end = memory_size & ~0x400000UL; /* align memory end to 4MB */ + /* + * We need some free virtual space to be able to do vmalloc. + * On a machine with 2GB memory we make sure that we have at + * least 128 MB free space for vmalloc. + */ + if (memory_end > 1920*1024*1024) + memory_end = 1920*1024*1024; +#else /* CONFIG_ARCH_S390X */ + memory_end = memory_size & ~0x200000UL; /* detected in head.s */ +#endif /* CONFIG_ARCH_S390X */ + + init_mm.start_code = PAGE_OFFSET; + init_mm.end_code = (unsigned long) &_etext; + init_mm.end_data = (unsigned long) &_edata; + init_mm.brk = (unsigned long) &_end; + + parse_cmdline_early(cmdline_p); + + setup_memory(); + setup_resources(); + setup_lowcore(); + cpu_init(); __cpu_logical_map[0] = S390_lowcore.cpu_data.cpu_addr; diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c index 8e723bc7f795..6ec5cd981e74 100644 --- a/arch/s390/mm/init.c +++ b/arch/s390/mm/init.c @@ -101,6 +101,7 @@ extern unsigned long _end; extern unsigned long __init_begin; extern unsigned long __init_end; +extern unsigned long __initdata zholes_size[]; /* * paging_init() sets up the page tables */ @@ -163,10 +164,13 @@ void __init paging_init(void) local_flush_tlb(); { - unsigned long zones_size[MAX_NR_ZONES] = { 0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES]; + memset(zones_size, 0, sizeof(zones_size)); zones_size[ZONE_DMA] = max_low_pfn; - free_area_init(zones_size); + free_area_init_node(0, &contig_page_data, zones_size, + __pa(PAGE_OFFSET) >> PAGE_SHIFT, + zholes_size); } return; } @@ -184,9 +188,10 @@ void __init paging_init(void) _KERN_REGION_TABLE; static const int ssm_mask = 0x04000000L; - unsigned long zones_size[MAX_NR_ZONES] = {0, 0, 0}; + unsigned long zones_size[MAX_NR_ZONES]; unsigned long dma_pfn, high_pfn; + memset(zones_size, 0, sizeof(zones_size)); dma_pfn = MAX_DMA_ADDRESS >> PAGE_SHIFT; high_pfn = max_low_pfn; @@ -198,8 +203,8 @@ void __init paging_init(void) } /* Initialize mem_map[]. */ - free_area_init(zones_size); - + free_area_init_node(0, &contig_page_data, zones_size, + __pa(PAGE_OFFSET) >> PAGE_SHIFT, zholes_size); /* * map whole physical memory to virtual memory (identity mapping)