diff options
Diffstat (limited to 'arch/s390/mm/mem_detect.c')
| -rw-r--r-- | arch/s390/mm/mem_detect.c | 65 | 
1 files changed, 65 insertions, 0 deletions
diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c new file mode 100644 index 00000000000..5535cfe0ee1 --- /dev/null +++ b/arch/s390/mm/mem_detect.c @@ -0,0 +1,65 @@ +/* + * Copyright IBM Corp. 2008, 2009 + * + * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> + */ + +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/memblock.h> +#include <linux/init.h> +#include <linux/debugfs.h> +#include <linux/seq_file.h> +#include <asm/ipl.h> +#include <asm/sclp.h> +#include <asm/setup.h> + +#define ADDR2G (1ULL << 31) + +#define CHUNK_READ_WRITE 0 +#define CHUNK_READ_ONLY  1 + +static inline void memblock_physmem_add(phys_addr_t start, phys_addr_t size) +{ +	memblock_add_range(&memblock.memory, start, size, 0, 0); +	memblock_add_range(&memblock.physmem, start, size, 0, 0); +} + +void __init detect_memory_memblock(void) +{ +	unsigned long long memsize, rnmax, rzm; +	unsigned long addr, size; +	int type; + +	rzm = sclp_get_rzm(); +	rnmax = sclp_get_rnmax(); +	memsize = rzm * rnmax; +	if (!rzm) +		rzm = 1ULL << 17; +	if (IS_ENABLED(CONFIG_32BIT)) { +		rzm = min(ADDR2G, rzm); +		memsize = min(ADDR2G, memsize); +	} +	max_physmem_end = memsize; +	addr = 0; +	/* keep memblock lists close to the kernel */ +	memblock_set_bottom_up(true); +	do { +		size = 0; +		type = tprot(addr); +		do { +			size += rzm; +			if (max_physmem_end && addr + size >= max_physmem_end) +				break; +		} while (type == tprot(addr + size)); +		if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) { +			if (max_physmem_end && (addr + size > max_physmem_end)) +				size = max_physmem_end - addr; +			memblock_physmem_add(addr, size); +		} +		addr += size; +	} while (addr < max_physmem_end); +	memblock_set_bottom_up(false); +	if (!max_physmem_end) +		max_physmem_end = memblock_end_of_DRAM(); +}  | 
