aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorHeiko Carstens <heiko.carstens@de.ibm.com>2008-07-14 03:59:21 -0400
committerHeiko Carstens <heiko.carstens@de.ibm.com>2008-07-14 04:02:17 -0400
commit23d1742179170b69e61ac9166248ffd64857e55a (patch)
tree5afb9b76b666f1543a6e8c42d760dfe0454e62e7 /arch/s390
parentef60cd13ecee0ccf2439d63013cbfc798aea2bb9 (diff)
[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>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/early.c109
-rw-r--r--arch/s390/kernel/mem_detect.c100
-rw-r--r--arch/s390/kernel/setup.c2
4 files changed, 103 insertions, 110 deletions
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 0fed81d91e03..50f657e77344 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -14,7 +14,7 @@ CFLAGS_ptrace.o += -DUTS_MACHINE='"$(UTS_MACHINE)"'
14 14
15obj-y := bitmap.o traps.o time.o process.o base.o early.o \ 15obj-y := bitmap.o traps.o time.o process.o base.o early.o \
16 setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ 16 setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \
17 s390_ext.o debug.o irq.o ipl.o dis.o diag.o 17 s390_ext.o debug.o irq.o ipl.o dis.o diag.o mem_detect.o
18 18
19obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) 19obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o)
20obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) 20obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o)
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index e22473993dc9..4c0ec7b46e37 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -192,100 +192,6 @@ static noinline __init void detect_machine_type(void)
192 machine_flags |= MACHINE_FLAG_KVM; 192 machine_flags |= MACHINE_FLAG_KVM;
193} 193}
194 194
195#ifdef CONFIG_64BIT
196static noinline __init int memory_fast_detect(void)
197{
198 unsigned long val0 = 0;
199 unsigned long val1 = 0xc;
200 int ret = -ENOSYS;
201
202 if (ipl_flags & IPL_NSS_VALID)
203 return -ENOSYS;
204
205 asm volatile(
206 " diag %1,%2,0x260\n"
207 "0: lhi %0,0\n"
208 "1:\n"
209 EX_TABLE(0b,1b)
210 : "+d" (ret), "+d" (val0), "+d" (val1) : : "cc");
211
212 if (ret || val0 != val1)
213 return -ENOSYS;
214
215 memory_chunk[0].size = val0 + 1;
216 return 0;
217}
218#else
219static inline int memory_fast_detect(void)
220{
221 return -ENOSYS;
222}
223#endif
224
225static inline __init unsigned long __tprot(unsigned long addr)
226{
227 int cc = -1;
228
229 asm volatile(
230 " tprot 0(%1),0\n"
231 "0: ipm %0\n"
232 " srl %0,28\n"
233 "1:\n"
234 EX_TABLE(0b,1b)
235 : "+d" (cc) : "a" (addr) : "cc");
236 return (unsigned long)cc;
237}
238
239/* Checking memory in 128KB increments. */
240#define CHUNK_INCR (1UL << 17)
241#define ADDR2G (1UL << 31)
242
243static noinline __init void find_memory_chunks(unsigned long memsize)
244{
245 unsigned long addr = 0, old_addr = 0;
246 unsigned long old_cc = CHUNK_READ_WRITE;
247 unsigned long cc;
248 int chunk = 0;
249
250 while (chunk < MEMORY_CHUNKS) {
251 cc = __tprot(addr);
252 while (cc == old_cc) {
253 addr += CHUNK_INCR;
254 if (memsize && addr >= memsize)
255 break;
256#ifndef CONFIG_64BIT
257 if (addr == ADDR2G)
258 break;
259#endif
260 cc = __tprot(addr);
261 }
262
263 if (old_addr != addr &&
264 (old_cc == CHUNK_READ_WRITE || old_cc == CHUNK_READ_ONLY)) {
265 memory_chunk[chunk].addr = old_addr;
266 memory_chunk[chunk].size = addr - old_addr;
267 memory_chunk[chunk].type = old_cc;
268 chunk++;
269 }
270
271 old_addr = addr;
272 old_cc = cc;
273
274#ifndef CONFIG_64BIT
275 if (addr == ADDR2G)
276 break;
277#endif
278 /*
279 * Finish memory detection at the first hole
280 * if storage size is unknown.
281 */
282 if (cc == -1UL && !memsize)
283 break;
284 if (memsize && addr >= memsize)
285 break;
286 }
287}
288
289static __init void early_pgm_check_handler(void) 195static __init void early_pgm_check_handler(void)
290{ 196{
291 unsigned long addr; 197 unsigned long addr;
@@ -465,8 +371,6 @@ static void __init setup_boot_command_line(void)
465 */ 371 */
466void __init startup_init(void) 372void __init startup_init(void)
467{ 373{
468 unsigned long long memsize;
469
470 ipl_save_parameters(); 374 ipl_save_parameters();
471 rescue_initrd(); 375 rescue_initrd();
472 clear_bss_section(); 376 clear_bss_section();
@@ -486,18 +390,7 @@ void __init startup_init(void)
486 detect_diag44(); 390 detect_diag44();
487 detect_machine_facilities(); 391 detect_machine_facilities();
488 setup_hpage(); 392 setup_hpage();
489 sclp_read_info_early();
490 sclp_facilities_detect(); 393 sclp_facilities_detect();
491 memsize = sclp_memory_detect(); 394 detect_memory_layout(memory_chunk);
492#ifndef CONFIG_64BIT
493 /*
494 * Can't deal with more than 2G in 31 bit addressing mode, so
495 * limit the value in order to avoid strange side effects.
496 */
497 if (memsize > ADDR2G)
498 memsize = ADDR2G;
499#endif
500 if (memory_fast_detect() < 0)
501 find_memory_chunks((unsigned long) memsize);
502 lockdep_on(); 395 lockdep_on();
503} 396}
diff --git a/arch/s390/kernel/mem_detect.c b/arch/s390/kernel/mem_detect.c
new file mode 100644
index 000000000000..18ed7abe16c5
--- /dev/null
+++ b/arch/s390/kernel/mem_detect.c
@@ -0,0 +1,100 @@
1/*
2 * Copyright IBM Corp. 2008
3 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
4 */
5
6#include <linux/kernel.h>
7#include <linux/module.h>
8#include <asm/ipl.h>
9#include <asm/sclp.h>
10#include <asm/setup.h>
11
12static int memory_fast_detect(struct mem_chunk *chunk)
13{
14 unsigned long val0 = 0;
15 unsigned long val1 = 0xc;
16 int rc = -EOPNOTSUPP;
17
18 if (ipl_flags & IPL_NSS_VALID)
19 return -EOPNOTSUPP;
20 asm volatile(
21 " diag %1,%2,0x260\n"
22 "0: lhi %0,0\n"
23 "1:\n"
24 EX_TABLE(0b,1b)
25 : "+d" (rc), "+d" (val0), "+d" (val1) : : "cc");
26
27 if (rc || val0 != val1)
28 return -EOPNOTSUPP;
29 chunk->size = val0 + 1;
30 return 0;
31}
32
33static inline int tprot(unsigned long addr)
34{
35 int rc = -EFAULT;
36
37 asm volatile(
38 " tprot 0(%1),0\n"
39 "0: ipm %0\n"
40 " srl %0,28\n"
41 "1:\n"
42 EX_TABLE(0b,1b)
43 : "+d" (rc) : "a" (addr) : "cc");
44 return rc;
45}
46
47#define ADDR2G (1ULL << 31)
48
49static void find_memory_chunks(struct mem_chunk chunk[])
50{
51 unsigned long long memsize, rnmax, rzm;
52 unsigned long addr = 0, size;
53 int i = 0, type;
54
55 rzm = sclp_get_rzm();
56 rnmax = sclp_get_rnmax();
57 memsize = rzm * rnmax;
58 if (!rzm)
59 rzm = 1ULL << 17;
60 if (sizeof(long) == 4) {
61 rzm = min(ADDR2G, rzm);
62 memsize = memsize ? min(ADDR2G, memsize) : ADDR2G;
63 }
64 do {
65 size = 0;
66 type = tprot(addr);
67 do {
68 size += rzm;
69 if (memsize && addr + size >= memsize)
70 break;
71 } while (type == tprot(addr + size));
72 if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) {
73 chunk[i].addr = addr;
74 chunk[i].size = size;
75 chunk[i].type = type;
76 i++;
77 }
78 addr += size;
79 } while (addr < memsize && i < MEMORY_CHUNKS);
80}
81
82void detect_memory_layout(struct mem_chunk chunk[])
83{
84 unsigned long flags, cr0;
85
86 memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk));
87 if (memory_fast_detect(&chunk[0]) == 0)
88 return;
89 /* Disable IRQs, DAT and low address protection so tprot does the
90 * right thing and we don't get scheduled away with low address
91 * protection disabled.
92 */
93 flags = __raw_local_irq_stnsm(0xf8);
94 __ctl_store(cr0, 0, 0);
95 __ctl_clear_bit(0, 28);
96 find_memory_chunks(chunk);
97 __ctl_load(cr0, 0, 0);
98 __raw_local_irq_ssm(flags);
99}
100EXPORT_SYMBOL(detect_memory_layout);
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index e3b4cdbae34e..9c92407f625c 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -77,7 +77,7 @@ unsigned long machine_flags;
77unsigned long elf_hwcap = 0; 77unsigned long elf_hwcap = 0;
78char elf_platform[ELF_PLATFORM_SIZE]; 78char elf_platform[ELF_PLATFORM_SIZE];
79 79
80struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS]; 80struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
81volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ 81volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
82static unsigned long __initdata memory_end; 82static unsigned long __initdata memory_end;
83 83