[S390] Move memory detection code to own file.
Move memory detection code to own file and also simplify it. Also add an interface which can be called at any time to get the current memory layout. This interface is needed by our kernel internal system dumper. Cc: Peter Oberparleiter <peter.oberparleiter@de.ibm.com> Cc: Michael Holzheu <holzheu@de.ibm.com> Cc: Frank Munzert <munzert@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com> Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
@@ -14,7 +14,7 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
|
||||
|
||||
obj-y := bitmap.o traps.o time.o process.o base.o early.o \
|
||||
setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
|
||||
s390_ext.o debug.o irq.o ipl.o dis.o diag.o
|
||||
s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o
|
||||
|
||||
obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
|
||||
obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
|
||||
|
@@ -192,100 +192,6 @@ static noinline __init void detect_machine_type(void)
|
||||
machine_flags |= MACHINE_FLAG_KVM;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_64BIT
|
||||
static noinline __init int memory_fast_detect(void)
|
||||
{
|
||||
unsigned long val0 = 0;
|
||||
unsigned long val1 = 0xc;
|
||||
int ret = -ENOSYS;
|
||||
|
||||
if (ipl_flags & IPL_NSS_VALID)
|
||||
return -ENOSYS;
|
||||
|
||||
asm volatile(
|
||||
" diag %1,%2,0x260\n"
|
||||
"0: lhi %0,0\n"
|
||||
"1:\n"
|
||||
EX_TABLE(0b,1b)
|
||||
: "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
|
||||
|
||||
if (ret || val0 != val1)
|
||||
return -ENOSYS;
|
||||
|
||||
memory_chunk[0].size = val0 + 1;
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
static inline int memory_fast_detect(void)
|
||||
{
|
||||
return -ENOSYS;
|
||||
}
|
||||
#endif
|
||||
|
||||
static inline __init unsigned long __tprot(unsigned long addr)
|
||||
{
|
||||
int cc = -1;
|
||||
|
||||
asm volatile(
|
||||
" tprot 0(%1),0\n"
|
||||
"0: ipm %0\n"
|
||||
" srl %0,28\n"
|
||||
"1:\n"
|
||||
EX_TABLE(0b,1b)
|
||||
: "+d" (cc) : "a" (addr) : "cc");
|
||||
return (unsigned long)cc;
|
||||
}
|
||||
|
||||
/* Checking memory in 128KB increments. */
|
||||
#define CHUNK_INCR (1UL << 17)
|
||||
#define ADDR2G (1UL << 31)
|
||||
|
||||
static noinline __init void find_memory_chunks(unsigned long memsize)
|
||||
{
|
||||
unsigned long addr = 0, old_addr = 0;
|
||||
unsigned long old_cc = CHUNK_READ_WRITE;
|
||||
unsigned long cc;
|
||||
int chunk = 0;
|
||||
|
||||
while (chunk < MEMORY_CHUNKS) {
|
||||
cc = __tprot(addr);
|
||||
while (cc == old_cc) {
|
||||
addr += CHUNK_INCR;
|
||||
if (memsize && addr >= memsize)
|
||||
break;
|
||||
#ifndef CONFIG_64BIT
|
||||
if (addr == ADDR2G)
|
||||
break;
|
||||
#endif
|
||||
cc = __tprot(addr);
|
||||
}
|
||||
|
||||
if (old_addr != addr &&
|
||||
(old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
|
||||
memory_chunk[chunk].addr = old_addr;
|
||||
memory_chunk[chunk].size = addr - old_addr;
|
||||
memory_chunk[chunk].type = old_cc;
|
||||
chunk++;
|
||||
}
|
||||
|
||||
old_addr = addr;
|
||||
old_cc = cc;
|
||||
|
||||
#ifndef CONFIG_64BIT
|
||||
if (addr == ADDR2G)
|
||||
break;
|
||||
#endif
|
||||
/*
|
||||
* Finish memory detection at the first hole
|
||||
* if storage size is unknown.
|
||||
*/
|
||||
if (cc == -1UL && !memsize)
|
||||
break;
|
||||
if (memsize && addr >= memsize)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static __init void early_pgm_check_handler(void)
|
||||
{
|
||||
unsigned long addr;
|
||||
@@ -465,8 +371,6 @@ static void __init setup_boot_command_line(void)
|
||||
*/
|
||||
void __init startup_init(void)
|
||||
{
|
||||
unsigned long long memsize;
|
||||
|
||||
ipl_save_parameters();
|
||||
rescue_initrd();
|
||||
clear_bss_section();
|
||||
@@ -486,18 +390,7 @@ void __init startup_init(void)
|
||||
detect_diag44();
|
||||
detect_machine_facilities();
|
||||
setup_hpage();
|
||||
sclp_read_info_early();
|
||||
sclp_facilities_detect();
|
||||
memsize = sclp_memory_detect();
|
||||
#ifndef CONFIG_64BIT
|
||||
/*
|
||||
* Can't deal with more than 2G in 31 bit addressing mode, so
|
||||
* limit the value in order to avoid strange side effects.
|
||||
*/
|
||||
if (memsize > ADDR2G)
|
||||
memsize = ADDR2G;
|
||||
#endif
|
||||
if (memory_fast_detect() < 0)
|
||||
find_memory_chunks((unsigned long) memsize);
|
||||
detect_memory_layout(memory_chunk);
|
||||
lockdep_on();
|
||||
}
|
||||
|
100
arch/s390/kernel/mem_detect.c
Normal file
100
arch/s390/kernel/mem_detect.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright IBM Corp. 2008
|
||||
* Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/ipl.h>
|
||||
#include <asm/sclp.h>
|
||||
#include <asm/setup.h>
|
||||
|
||||
static int memory_fast_detect(struct mem_chunk *chunk)
|
||||
{
|
||||
unsigned long val0 = 0;
|
||||
unsigned long val1 = 0xc;
|
||||
int rc = -EOPNOTSUPP;
|
||||
|
||||
if (ipl_flags & IPL_NSS_VALID)
|
||||
return -EOPNOTSUPP;
|
||||
asm volatile(
|
||||
" diag %1,%2,0x260\n"
|
||||
"0: lhi %0,0\n"
|
||||
"1:\n"
|
||||
EX_TABLE(0b,1b)
|
||||
: "+d" (rc), "+d" (val0), "+d" (val1) : : "cc");
|
||||
|
||||
if (rc || val0 != val1)
|
||||
return -EOPNOTSUPP;
|
||||
chunk->size = val0 + 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int tprot(unsigned long addr)
|
||||
{
|
||||
int rc = -EFAULT;
|
||||
|
||||
asm volatile(
|
||||
" tprot 0(%1),0\n"
|
||||
"0: ipm %0\n"
|
||||
" srl %0,28\n"
|
||||
"1:\n"
|
||||
EX_TABLE(0b,1b)
|
||||
: "+d" (rc) : "a" (addr) : "cc");
|
||||
return rc;
|
||||
}
|
||||
|
||||
#define ADDR2G (1ULL << 31)
|
||||
|
||||
static void find_memory_chunks(struct mem_chunk chunk[])
|
||||
{
|
||||
unsigned long long memsize, rnmax, rzm;
|
||||
unsigned long addr = 0, size;
|
||||
int i = 0, type;
|
||||
|
||||
rzm = sclp_get_rzm();
|
||||
rnmax = sclp_get_rnmax();
|
||||
memsize = rzm * rnmax;
|
||||
if (!rzm)
|
||||
rzm = 1ULL << 17;
|
||||
if (sizeof(long) == 4) {
|
||||
rzm = min(ADDR2G, rzm);
|
||||
memsize = memsize ? min(ADDR2G, memsize) : ADDR2G;
|
||||
}
|
||||
do {
|
||||
size = 0;
|
||||
type = tprot(addr);
|
||||
do {
|
||||
size += rzm;
|
||||
if (memsize && addr + size >= memsize)
|
||||
break;
|
||||
} while (type == tprot(addr + size));
|
||||
if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) {
|
||||
chunk[i].addr = addr;
|
||||
chunk[i].size = size;
|
||||
chunk[i].type = type;
|
||||
i++;
|
||||
}
|
||||
addr += size;
|
||||
} while (addr < memsize && i < MEMORY_CHUNKS);
|
||||
}
|
||||
|
||||
void detect_memory_layout(struct mem_chunk chunk[])
|
||||
{
|
||||
unsigned long flags, cr0;
|
||||
|
||||
memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk));
|
||||
if (memory_fast_detect(&chunk[0]) == 0)
|
||||
return;
|
||||
/* Disable IRQs, DAT and low address protection so tprot does the
|
||||
* right thing and we don't get scheduled away with low address
|
||||
* protection disabled.
|
||||
*/
|
||||
flags = __raw_local_irq_stnsm(0xf8);
|
||||
__ctl_store(cr0, 0, 0);
|
||||
__ctl_clear_bit(0, 28);
|
||||
find_memory_chunks(chunk);
|
||||
__ctl_load(cr0, 0, 0);
|
||||
__raw_local_irq_ssm(flags);
|
||||
}
|
||||
EXPORT_SYMBOL(detect_memory_layout);
|
@@ -77,7 +77,7 @@ unsigned long machine_flags;
|
||||
unsigned long elf_hwcap = 0;
|
||||
char elf_platform[ELF_PLATFORM_SIZE];
|
||||
|
||||
struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS];
|
||||
struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
|
||||
volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
|
||||
static unsigned long __initdata memory_end;
|
||||
|
||||
|
Reference in New Issue
Block a user