diff options
Diffstat (limited to 'arch/s390/kernel/setup.c')
| -rw-r--r-- | arch/s390/kernel/setup.c | 561 | 
1 files changed, 206 insertions, 355 deletions
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index aeed8a61fa0..1e2264b46e4 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c @@ -47,7 +47,6 @@  #include <linux/compat.h>  #include <asm/ipl.h> -#include <asm/uaccess.h>  #include <asm/facility.h>  #include <asm/smp.h>  #include <asm/mmu_context.h> @@ -64,18 +63,6 @@  #include <asm/sclp.h>  #include "entry.h" -long psw_kernel_bits	= PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_ASC_PRIMARY | -			  PSW_MASK_EA | PSW_MASK_BA; -long psw_user_bits	= PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | -			  PSW_DEFAULT_KEY | PSW_MASK_BASE | PSW_MASK_MCHECK | -			  PSW_MASK_PSTATE | PSW_ASC_HOME; - -/* - * User copy operations. - */ -struct uaccess_ops uaccess; -EXPORT_SYMBOL(uaccess); -  /*   * Machine setup..   */ @@ -91,10 +78,9 @@ EXPORT_SYMBOL(console_irq);  unsigned long elf_hwcap = 0;  char elf_platform[ELF_PLATFORM_SIZE]; -struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; -  int __initdata memory_end_set;  unsigned long __initdata memory_end; +unsigned long __initdata max_physmem_end;  unsigned long VMALLOC_START;  EXPORT_SYMBOL(VMALLOC_START); @@ -225,7 +211,7 @@ static void __init conmode_default(void)  	}  } -#ifdef CONFIG_ZFCPDUMP +#ifdef CONFIG_CRASH_DUMP  static void __init setup_zfcpdump(void)  {  	if (ipl_info.type != IPL_TYPE_FCP_DUMP) @@ -237,7 +223,7 @@ static void __init setup_zfcpdump(void)  }  #else  static inline void setup_zfcpdump(void) {} -#endif /* CONFIG_ZFCPDUMP */ +#endif /* CONFIG_CRASH_DUMP */   /*   * Reboot, halt and power_off stubs. They just call _machine_restart, @@ -286,6 +272,7 @@ EXPORT_SYMBOL_GPL(pm_power_off);  static int __init early_parse_mem(char *p)  {  	memory_end = memparse(p, &p); +	memory_end &= PAGE_MASK;  	memory_end_set = 1;  	return 0;  } @@ -300,43 +287,6 @@ static int __init parse_vmalloc(char *arg)  }  early_param("vmalloc", parse_vmalloc); -unsigned int s390_user_mode = PRIMARY_SPACE_MODE; -EXPORT_SYMBOL_GPL(s390_user_mode); - -static void __init set_user_mode_primary(void) -{ -	psw_kernel_bits = (psw_kernel_bits & ~PSW_MASK_ASC) | PSW_ASC_HOME; -	psw_user_bits = (psw_user_bits & ~PSW_MASK_ASC) | PSW_ASC_PRIMARY; -#ifdef CONFIG_COMPAT -	psw32_user_bits = -		(psw32_user_bits & ~PSW32_MASK_ASC) | PSW32_ASC_PRIMARY; -#endif -	uaccess = MACHINE_HAS_MVCOS ? uaccess_mvcos_switch : uaccess_pt; -} - -static int __init early_parse_user_mode(char *p) -{ -	if (p && strcmp(p, "primary") == 0) -		s390_user_mode = PRIMARY_SPACE_MODE; -	else if (!p || strcmp(p, "home") == 0) -		s390_user_mode = HOME_SPACE_MODE; -	else -		return 1; -	return 0; -} -early_param("user_mode", early_parse_user_mode); - -static void __init setup_addressing_mode(void) -{ -	if (s390_user_mode != PRIMARY_SPACE_MODE) -		return; -	set_user_mode_primary(); -	if (MACHINE_HAS_MVCOS) -		pr_info("Address spaces switched, mvcos available\n"); -	else -		pr_info("Address spaces switched, mvcos not available\n"); -} -  void *restart_stack __attribute__((__section__(".data")));  static void __init setup_lowcore(void) @@ -348,24 +298,24 @@ static void __init setup_lowcore(void)  	 */  	BUILD_BUG_ON(sizeof(struct _lowcore) != LC_PAGES * 4096);  	lc = __alloc_bootmem_low(LC_PAGES * PAGE_SIZE, LC_PAGES * PAGE_SIZE, 0); -	lc->restart_psw.mask = psw_kernel_bits; +	lc->restart_psw.mask = PSW_KERNEL_BITS;  	lc->restart_psw.addr =  		PSW_ADDR_AMODE | (unsigned long) restart_int_handler; -	lc->external_new_psw.mask = psw_kernel_bits | +	lc->external_new_psw.mask = PSW_KERNEL_BITS |  		PSW_MASK_DAT | PSW_MASK_MCHECK;  	lc->external_new_psw.addr =  		PSW_ADDR_AMODE | (unsigned long) ext_int_handler; -	lc->svc_new_psw.mask = psw_kernel_bits | +	lc->svc_new_psw.mask = PSW_KERNEL_BITS |  		PSW_MASK_DAT | PSW_MASK_IO | PSW_MASK_EXT | PSW_MASK_MCHECK;  	lc->svc_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) system_call; -	lc->program_new_psw.mask = psw_kernel_bits | +	lc->program_new_psw.mask = PSW_KERNEL_BITS |  		PSW_MASK_DAT | PSW_MASK_MCHECK;  	lc->program_new_psw.addr =  		PSW_ADDR_AMODE | (unsigned long) pgm_check_handler; -	lc->mcck_new_psw.mask = psw_kernel_bits; +	lc->mcck_new_psw.mask = PSW_KERNEL_BITS;  	lc->mcck_new_psw.addr =  		PSW_ADDR_AMODE | (unsigned long) mcck_int_handler; -	lc->io_new_psw.mask = psw_kernel_bits | +	lc->io_new_psw.mask = PSW_KERNEL_BITS |  		PSW_MASK_DAT | PSW_MASK_MCHECK;  	lc->io_new_psw.addr = PSW_ADDR_AMODE | (unsigned long) io_int_handler;  	lc->clock_comparator = -1ULL; @@ -408,7 +358,7 @@ static void __init setup_lowcore(void)  	/*  	 * Set up PSW restart to call ipl.c:do_restart(). Copy the relevant -	 * restart data to the absolute zero lowcore. This is necesary if +	 * restart data to the absolute zero lowcore. This is necessary if  	 * PSW restart is done on an offline CPU that has lowcore zero.  	 */  	lc->restart_stack = (unsigned long) restart_stack; @@ -423,6 +373,10 @@ static void __init setup_lowcore(void)  	mem_assign_absolute(S390_lowcore.restart_source, lc->restart_source);  	mem_assign_absolute(S390_lowcore.restart_psw, lc->restart_psw); +#ifdef CONFIG_SMP +	lc->spinlock_lockval = arch_spin_lockval(0); +#endif +  	set_prefix((u32)(unsigned long) lc);  	lowcore_ptr[0] = lc;  } @@ -451,7 +405,8 @@ static struct resource __initdata *standard_resources[] = {  static void __init setup_resources(void)  {  	struct resource *res, *std_res, *sub_res; -	int i, j; +	struct memblock_region *reg; +	int j;  	code_resource.start = (unsigned long) &_text;  	code_resource.end = (unsigned long) &_etext - 1; @@ -460,24 +415,13 @@ static void __init setup_resources(void)  	bss_resource.start = (unsigned long) &__bss_start;  	bss_resource.end = (unsigned long) &__bss_stop - 1; -	for (i = 0; i < MEMORY_CHUNKS; i++) { -		if (!memory_chunk[i].size) -			continue; +	for_each_memblock(memory, reg) {  		res = alloc_bootmem_low(sizeof(*res));  		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 = res->start + memory_chunk[i].size - 1; + +		res->name = "System RAM"; +		res->start = reg->base; +		res->end = reg->base + reg->size - 1;  		request_resource(&iomem_resource, res);  		for (j = 0; j < ARRAY_SIZE(standard_resources); j++) { @@ -501,47 +445,11 @@ static void __init setup_resources(void)  static void __init setup_memory_end(void)  {  	unsigned long vmax, vmalloc_size, tmp; -	unsigned long real_memory_size = 0; -	int i; - - -#ifdef CONFIG_ZFCPDUMP -	if (ipl_info.type == IPL_TYPE_FCP_DUMP && !OLDMEM_BASE) { -		memory_end = ZFCPDUMP_HSA_SIZE; -		memory_end_set = 1; -	} -#endif -	memory_end &= PAGE_MASK; - -	/* -	 * Make sure all chunks are MAX_ORDER aligned so we don't need the -	 * extra checks that HOLES_IN_ZONE would require. -	 */ -	for (i = 0; i < MEMORY_CHUNKS; i++) { -		unsigned long start, end; -		struct mem_chunk *chunk; -		unsigned long align; - -		chunk = &memory_chunk[i]; -		if (!chunk->size) -			continue; -		align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1); -		start = (chunk->addr + align - 1) & ~(align - 1); -		end = (chunk->addr + chunk->size) & ~(align - 1); -		if (start >= end) -			memset(chunk, 0, sizeof(*chunk)); -		else { -			chunk->addr = start; -			chunk->size = end - start; -		} -		real_memory_size = max(real_memory_size, -				       chunk->addr + chunk->size); -	}  	/* Choose kernel address space layout: 2, 3, or 4 levels. */  #ifdef CONFIG_64BIT  	vmalloc_size = VMALLOC_END ?: (128UL << 30) - MODULES_LEN; -	tmp = (memory_end ?: real_memory_size) / PAGE_SIZE; +	tmp = (memory_end ?: max_physmem_end) / PAGE_SIZE;  	tmp = tmp * (sizeof(struct page) + PAGE_SIZE) + vmalloc_size;  	if (tmp <= (1UL << 42))  		vmax = 1UL << 42;	/* 3-level kernel page table */ @@ -569,21 +477,11 @@ static void __init setup_memory_end(void)  	vmemmap = (struct page *) tmp;  	/* Take care that memory_end is set and <= vmemmap */ -	memory_end = min(memory_end ?: real_memory_size, tmp); +	memory_end = min(memory_end ?: max_physmem_end, tmp); +	max_pfn = max_low_pfn = PFN_DOWN(memory_end); +	memblock_remove(memory_end, ULONG_MAX); -	/* Fixup memory chunk array to fit into 0..memory_end */ -	for (i = 0; i < MEMORY_CHUNKS; i++) { -		struct mem_chunk *chunk = &memory_chunk[i]; - -		if (!chunk->size) -			continue; -		if (chunk->addr >= memory_end) { -			memset(chunk, 0, sizeof(*chunk)); -			continue; -		} -		if (chunk->addr + chunk->size > memory_end) -			chunk->size = memory_end - chunk->addr; -	} +	pr_notice("Max memory size: %luMB\n", memory_end >> 20);  }  static void __init setup_vmcoreinfo(void) @@ -594,89 +492,6 @@ static void __init setup_vmcoreinfo(void)  #ifdef CONFIG_CRASH_DUMP  /* - * Find suitable location for crashkernel memory - */ -static unsigned long __init find_crash_base(unsigned long crash_size, -					    char **msg) -{ -	unsigned long crash_base; -	struct mem_chunk *chunk; -	int i; - -	if (memory_chunk[0].size < crash_size) { -		*msg = "first memory chunk must be at least crashkernel size"; -		return 0; -	} -	if (OLDMEM_BASE && crash_size == OLDMEM_SIZE) -		return OLDMEM_BASE; - -	for (i = MEMORY_CHUNKS - 1; i >= 0; i--) { -		chunk = &memory_chunk[i]; -		if (chunk->size == 0) -			continue; -		if (chunk->type != CHUNK_READ_WRITE) -			continue; -		if (chunk->size < crash_size) -			continue; -		crash_base = (chunk->addr + chunk->size) - crash_size; -		if (crash_base < crash_size) -			continue; -		if (crash_base < ZFCPDUMP_HSA_SIZE_MAX) -			continue; -		if (crash_base < (unsigned long) INITRD_START + INITRD_SIZE) -			continue; -		return crash_base; -	} -	*msg = "no suitable area found"; -	return 0; -} - -/* - * Check if crash_base and crash_size is valid - */ -static int __init verify_crash_base(unsigned long crash_base, -				    unsigned long crash_size, -				    char **msg) -{ -	struct mem_chunk *chunk; -	int i; - -	/* -	 * Because we do the swap to zero, we must have at least 'crash_size' -	 * bytes free space before crash_base -	 */ -	if (crash_size > crash_base) { -		*msg = "crashkernel offset must be greater than size"; -		return -EINVAL; -	} - -	/* First memory chunk must be at least crash_size */ -	if (memory_chunk[0].size < crash_size) { -		*msg = "first memory chunk must be at least crashkernel size"; -		return -EINVAL; -	} -	/* Check if we fit into the respective memory chunk */ -	for (i = 0; i < MEMORY_CHUNKS; i++) { -		chunk = &memory_chunk[i]; -		if (chunk->size == 0) -			continue; -		if (crash_base < chunk->addr) -			continue; -		if (crash_base >= chunk->addr + chunk->size) -			continue; -		/* we have found the memory chunk */ -		if (crash_base + crash_size > chunk->addr + chunk->size) { -			*msg = "selected memory chunk is too small for " -				"crashkernel memory"; -			return -EINVAL; -		} -		return 0; -	} -	*msg = "invalid memory range specified"; -	return -EINVAL; -} - -/*   * When kdump is enabled, we have to ensure that no memory from   * the area [0 - crashkernel memory size] and   * [crashk_res.start - crashk_res.end] is set offline. @@ -702,23 +517,44 @@ static struct notifier_block kdump_mem_nb = {  #endif  /* + * Make sure that the area behind memory_end is protected + */ +static void reserve_memory_end(void) +{ +#ifdef CONFIG_CRASH_DUMP +	if (ipl_info.type == IPL_TYPE_FCP_DUMP && +	    !OLDMEM_BASE && sclp_get_hsa_size()) { +		memory_end = sclp_get_hsa_size(); +		memory_end &= PAGE_MASK; +		memory_end_set = 1; +	} +#endif +	if (!memory_end_set) +		return; +	memblock_reserve(memory_end, ULONG_MAX); +} + +/*   * Make sure that oldmem, where the dump is stored, is protected   */  static void reserve_oldmem(void)  {  #ifdef CONFIG_CRASH_DUMP -	unsigned long real_size = 0; -	int i; - -	if (!OLDMEM_BASE) -		return; -	for (i = 0; i < MEMORY_CHUNKS; i++) { -		struct mem_chunk *chunk = &memory_chunk[i]; +	if (OLDMEM_BASE) +		/* Forget all memory above the running kdump system */ +		memblock_reserve(OLDMEM_SIZE, (phys_addr_t)ULONG_MAX); +#endif +} -		real_size = max(real_size, chunk->addr + chunk->size); -	} -	create_mem_hole(memory_chunk, OLDMEM_BASE, OLDMEM_SIZE); -	create_mem_hole(memory_chunk, OLDMEM_SIZE, real_size - OLDMEM_SIZE); +/* + * Make sure that oldmem, where the dump is stored, is protected + */ +static void remove_oldmem(void) +{ +#ifdef CONFIG_CRASH_DUMP +	if (OLDMEM_BASE) +		/* Forget all memory above the running kdump system */ +		memblock_remove(OLDMEM_SIZE, (phys_addr_t)ULONG_MAX);  #endif  } @@ -729,167 +565,132 @@ static void __init reserve_crashkernel(void)  {  #ifdef CONFIG_CRASH_DUMP  	unsigned long long crash_base, crash_size; -	char *msg = NULL; +	phys_addr_t low, high;  	int rc;  	rc = parse_crashkernel(boot_command_line, memory_end, &crash_size,  			       &crash_base); -	if (rc || crash_size == 0) -		return; +  	crash_base = ALIGN(crash_base, KEXEC_CRASH_MEM_ALIGN);  	crash_size = ALIGN(crash_size, KEXEC_CRASH_MEM_ALIGN); -	if (register_memory_notifier(&kdump_mem_nb)) +	if (rc || crash_size == 0)  		return; -	if (!crash_base) -		crash_base = find_crash_base(crash_size, &msg); -	if (!crash_base) { -		pr_info("crashkernel reservation failed: %s\n", msg); -		unregister_memory_notifier(&kdump_mem_nb); + +	if (memblock.memory.regions[0].size < crash_size) { +		pr_info("crashkernel reservation failed: %s\n", +			"first memory chunk must be at least crashkernel size");  		return;  	} -	if (verify_crash_base(crash_base, crash_size, &msg)) { -		pr_info("crashkernel reservation failed: %s\n", msg); -		unregister_memory_notifier(&kdump_mem_nb); + +	low = crash_base ?: OLDMEM_BASE; +	high = low + crash_size; +	if (low >= OLDMEM_BASE && high <= OLDMEM_BASE + OLDMEM_SIZE) { +		/* The crashkernel fits into OLDMEM, reuse OLDMEM */ +		crash_base = low; +	} else { +		/* Find suitable area in free memory */ +		low = max_t(unsigned long, crash_size, sclp_get_hsa_size()); +		high = crash_base ? crash_base + crash_size : ULONG_MAX; + +		if (crash_base && crash_base < low) { +			pr_info("crashkernel reservation failed: %s\n", +				"crash_base too low"); +			return; +		} +		low = crash_base ?: low; +		crash_base = memblock_find_in_range(low, high, crash_size, +						    KEXEC_CRASH_MEM_ALIGN); +	} + +	if (!crash_base) { +		pr_info("crashkernel reservation failed: %s\n", +			"no suitable area found");  		return;  	} + +	if (register_memory_notifier(&kdump_mem_nb)) +		return; +  	if (!OLDMEM_BASE && MACHINE_IS_VM)  		diag10_range(PFN_DOWN(crash_base), PFN_DOWN(crash_size));  	crashk_res.start = crash_base;  	crashk_res.end = crash_base + crash_size - 1;  	insert_resource(&iomem_resource, &crashk_res); -	create_mem_hole(memory_chunk, crash_base, crash_size); +	memblock_remove(crash_base, crash_size);  	pr_info("Reserving %lluMB of memory at %lluMB "  		"for crashkernel (System RAM: %luMB)\n", -		crash_size >> 20, crash_base >> 20, memory_end >> 20); +		crash_size >> 20, crash_base >> 20, +		(unsigned long)memblock.memory.total_size >> 20);  	os_info_crashkernel_add(crash_base, crash_size);  #endif  } -static void __init setup_memory(void) +/* + * Reserve the initrd from being used by memblock + */ +static void __init reserve_initrd(void)  { -        unsigned long bootmap_size; -	unsigned long start_pfn, end_pfn; -	int i; +#ifdef CONFIG_BLK_DEV_INITRD +	initrd_start = INITRD_START; +	initrd_end = initrd_start + INITRD_SIZE; +	memblock_reserve(INITRD_START, INITRD_SIZE); +#endif +} -	/* -	 * partially used pages are not usable - thus -	 * we are rounding upwards: -	 */ +/* + * Check for initrd being in usable memory + */ +static void __init check_initrd(void) +{ +#ifdef CONFIG_BLK_DEV_INITRD +	if (INITRD_START && INITRD_SIZE && +	    !memblock_is_region_memory(INITRD_START, INITRD_SIZE)) { +		pr_err("initrd does not fit memory.\n"); +		memblock_free(INITRD_START, INITRD_SIZE); +		initrd_start = initrd_end = 0; +	} +#endif +} + +/* + * Reserve all kernel text + */ +static void __init reserve_kernel(void) +{ +	unsigned long start_pfn;  	start_pfn = PFN_UP(__pa(&_end)); -	end_pfn = max_pfn = PFN_DOWN(memory_end); -#ifdef CONFIG_BLK_DEV_INITRD  	/* -	 * Move the initrd in case the bitmap of the bootmem allocater -	 * would overwrite it. +	 * Reserve memory used for lowcore/command line/kernel image.  	 */ +	memblock_reserve(0, (unsigned long)_ehead); +	memblock_reserve((unsigned long)_stext, PFN_PHYS(start_pfn) +			 - (unsigned long)_stext); +} -	if (INITRD_START && INITRD_SIZE) { -		unsigned long bmap_size; -		unsigned long start; - -		bmap_size = bootmem_bootmap_pages(end_pfn - start_pfn + 1); -		bmap_size = PFN_PHYS(bmap_size); - -		if (PFN_PHYS(start_pfn) + bmap_size > INITRD_START) { -			start = PFN_PHYS(start_pfn) + bmap_size + PAGE_SIZE; - +static void __init reserve_elfcorehdr(void) +{  #ifdef CONFIG_CRASH_DUMP -			if (OLDMEM_BASE) { -				/* Move initrd behind kdump oldmem */ -				if (start + INITRD_SIZE > OLDMEM_BASE && -				    start < OLDMEM_BASE + OLDMEM_SIZE) -					start = OLDMEM_BASE + OLDMEM_SIZE; -			} -#endif -			if (start + INITRD_SIZE > memory_end) { -				pr_err("initrd extends beyond end of " -				       "memory (0x%08lx > 0x%08lx) " -				       "disabling initrd\n", -				       start + INITRD_SIZE, memory_end); -				INITRD_START = INITRD_SIZE = 0; -			} else { -				pr_info("Moving initrd (0x%08lx -> " -					"0x%08lx, size: %ld)\n", -					INITRD_START, start, INITRD_SIZE); -				memmove((void *) start, (void *) INITRD_START, -					INITRD_SIZE); -				INITRD_START = start; -			} -		} -	} +	if (is_kdump_kernel()) +		memblock_reserve(elfcorehdr_addr - OLDMEM_BASE, +				 PAGE_ALIGN(elfcorehdr_size));  #endif +} -	/* -	 * Initialize the boot-time allocator -	 */ -	bootmap_size = init_bootmem(start_pfn, end_pfn); +static void __init setup_memory(void) +{ +	struct memblock_region *reg;  	/* -	 * Register RAM areas with the bootmem allocator. +	 * Init storage key for present memory  	 */ - -	for (i = 0; i < MEMORY_CHUNKS; i++) { -		unsigned long start_chunk, end_chunk, pfn; - -		if (!memory_chunk[i].size) -			continue; -		start_chunk = PFN_DOWN(memory_chunk[i].addr); -		end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size); -		end_chunk = min(end_chunk, end_pfn); -		if (start_chunk >= end_chunk) -			continue; -		memblock_add_node(PFN_PHYS(start_chunk), -				  PFN_PHYS(end_chunk - start_chunk), 0); -		pfn = max(start_chunk, start_pfn); -		storage_key_init_range(PFN_PHYS(pfn), PFN_PHYS(end_chunk)); +	for_each_memblock(memory, reg) { +		storage_key_init_range(reg->base, reg->base + reg->size);  	} -  	psw_set_key(PAGE_DEFAULT_KEY); -	free_bootmem_with_active_regions(0, max_pfn); - -	/* -	 * Reserve memory used for lowcore/command line/kernel image. -	 */ -	reserve_bootmem(0, (unsigned long)_ehead, BOOTMEM_DEFAULT); -	reserve_bootmem((unsigned long)_stext, -			PFN_PHYS(start_pfn) - (unsigned long)_stext, -			BOOTMEM_DEFAULT); -	/* -	 * 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, -			BOOTMEM_DEFAULT); - -#ifdef CONFIG_CRASH_DUMP -	if (crashk_res.start) -		reserve_bootmem(crashk_res.start, -				crashk_res.end - crashk_res.start + 1, -				BOOTMEM_DEFAULT); -	if (is_kdump_kernel()) -		reserve_bootmem(elfcorehdr_addr - OLDMEM_BASE, -				PAGE_ALIGN(elfcorehdr_size), BOOTMEM_DEFAULT); -#endif -#ifdef CONFIG_BLK_DEV_INITRD -	if (INITRD_START && INITRD_SIZE) { -		if (INITRD_START + INITRD_SIZE <= memory_end) { -			reserve_bootmem(INITRD_START, INITRD_SIZE, -					BOOTMEM_DEFAULT); -			initrd_start = INITRD_START; -			initrd_end = initrd_start + INITRD_SIZE; -		} else { -			pr_err("initrd extends beyond end of " -			       "memory (0x%08lx > 0x%08lx) " -			       "disabling initrd\n", -			       initrd_start + INITRD_SIZE, memory_end); -			initrd_start = initrd_end = 0; -		} -	} -#endif +	/* Only cosmetics */ +	memblock_enforce_memory_limit(memblock_end_of_DRAM());  }  /* @@ -1038,29 +839,47 @@ void __init setup_arch(char **cmdline_p)          ROOT_DEV = Root_RAM0; +	/* Is init_mm really needed? */  	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; -	if (MACHINE_HAS_MVCOS) -		memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess)); -	else -		memcpy(&uaccess, &uaccess_std, sizeof(uaccess)); -  	parse_early_param(); -	detect_memory_layout(memory_chunk, memory_end);  	os_info_init();  	setup_ipl(); + +	/* Do some memory reservations *before* memory is added to memblock */ +	reserve_memory_end();  	reserve_oldmem(); +	reserve_kernel(); +	reserve_initrd(); +	reserve_elfcorehdr(); +	memblock_allow_resize(); + +	/* Get information about *all* installed memory */ +	detect_memory_memblock(); + +	remove_oldmem(); + +	/* +	 * Make sure all chunks are MAX_ORDER aligned so we don't need the +	 * extra checks that HOLES_IN_ZONE would require. +	 * +	 * Is this still required? +	 */ +	memblock_trim_memory(1UL << (MAX_ORDER - 1 + PAGE_SHIFT)); +  	setup_memory_end(); -	setup_addressing_mode(); -	reserve_crashkernel();  	setup_memory(); + +	check_initrd(); +	reserve_crashkernel(); +  	setup_resources();  	setup_vmcoreinfo();  	setup_lowcore(); - +	smp_fill_possible_mask();          cpu_init();  	s390_init_cpu_topology(); @@ -1081,3 +900,35 @@ void __init setup_arch(char **cmdline_p)  	/* Setup zfcpdump support */  	setup_zfcpdump();  } + +#ifdef CONFIG_32BIT +static int no_removal_warning __initdata; + +static int __init parse_no_removal_warning(char *str) +{ +	no_removal_warning = 1; +	return 0; +} +__setup("no_removal_warning", parse_no_removal_warning); + +static int __init removal_warning(void) +{ +	if (no_removal_warning) +		return 0; +	printk(KERN_ALERT "\n\n"); +	printk(KERN_CONT "Warning - you are using a 31 bit kernel!\n\n"); +	printk(KERN_CONT "We plan to remove 31 bit kernel support from the kernel sources in March 2015.\n"); +	printk(KERN_CONT "Currently we assume that nobody is using the 31 bit kernel on old 31 bit\n"); +	printk(KERN_CONT "hardware anymore. If you think that the code should not be removed and also\n"); +	printk(KERN_CONT "future versions of the Linux kernel should be able to run in 31 bit mode\n"); +	printk(KERN_CONT "please let us know. Please write to:\n"); +	printk(KERN_CONT "linux390@de.ibm.com (mail address) and/or\n"); +	printk(KERN_CONT "linux-s390@vger.kernel.org (mailing list).\n\n"); +	printk(KERN_CONT "Thank you!\n\n"); +	printk(KERN_CONT "If this kernel runs on a 64 bit machine you may consider using a 64 bit kernel.\n"); +	printk(KERN_CONT "This message can be disabled with the \"no_removal_warning\" kernel parameter.\n"); +	schedule_timeout_uninterruptible(300 * HZ); +	return 0; +} +early_initcall(removal_warning); +#endif  | 
