aboutsummaryrefslogtreecommitdiffstats
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
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>
-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
-rw-r--r--drivers/s390/char/sclp_cmd.c33
-rw-r--r--include/asm-s390/sclp.h4
-rw-r--r--include/asm-s390/setup.h6
7 files changed, 127 insertions, 129 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
diff --git a/drivers/s390/char/sclp_cmd.c b/drivers/s390/char/sclp_cmd.c
index 4f45884c92c3..0c2b77493db4 100644
--- a/drivers/s390/char/sclp_cmd.c
+++ b/drivers/s390/char/sclp_cmd.c
@@ -67,7 +67,7 @@ out:
67 return rc; 67 return rc;
68} 68}
69 69
70void __init sclp_read_info_early(void) 70static void __init sclp_read_info_early(void)
71{ 71{
72 int rc; 72 int rc;
73 int i; 73 int i;
@@ -97,30 +97,33 @@ void __init sclp_read_info_early(void)
97 97
98void __init sclp_facilities_detect(void) 98void __init sclp_facilities_detect(void)
99{ 99{
100 if (!early_read_info_sccb_valid)
101 return;
102 sclp_facilities = early_read_info_sccb.facilities;
103 sclp_fac84 = early_read_info_sccb.fac84;
104}
105
106unsigned long long __init sclp_memory_detect(void)
107{
108 unsigned long long memsize;
109 struct read_info_sccb *sccb; 100 struct read_info_sccb *sccb;
110 101
102 sclp_read_info_early();
111 if (!early_read_info_sccb_valid) 103 if (!early_read_info_sccb_valid)
112 return 0; 104 return;
105
113 sccb = &early_read_info_sccb; 106 sccb = &early_read_info_sccb;
107 sclp_facilities = sccb->facilities;
108 sclp_fac84 = sccb->fac84;
114 rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; 109 rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2;
115 rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; 110 rzm = sccb->rnsize ? sccb->rnsize : sccb->rnsize2;
116 rzm <<= 20; 111 rzm <<= 20;
117 memsize = rzm * rnmax; 112}
118 return memsize; 113
114unsigned long long sclp_get_rnmax(void)
115{
116 return rnmax;
117}
118
119unsigned long long sclp_get_rzm(void)
120{
121 return rzm;
119} 122}
120 123
121/* 124/*
122 * This function will be called after sclp_memory_detect(), which gets called 125 * This function will be called after sclp_facilities_detect(), which gets
123 * early from early.c code. Therefore the sccb should have valid contents. 126 * called from early.c code. Therefore the sccb should have valid contents.
124 */ 127 */
125void __init sclp_get_ipl_info(struct sclp_ipl_info *info) 128void __init sclp_get_ipl_info(struct sclp_ipl_info *info)
126{ 129{
diff --git a/include/asm-s390/sclp.h b/include/asm-s390/sclp.h
index b5f2843013a3..fed7bee650a0 100644
--- a/include/asm-s390/sclp.h
+++ b/include/asm-s390/sclp.h
@@ -45,9 +45,9 @@ struct sclp_cpu_info {
45int sclp_get_cpu_info(struct sclp_cpu_info *info); 45int sclp_get_cpu_info(struct sclp_cpu_info *info);
46int sclp_cpu_configure(u8 cpu); 46int sclp_cpu_configure(u8 cpu);
47int sclp_cpu_deconfigure(u8 cpu); 47int sclp_cpu_deconfigure(u8 cpu);
48void sclp_read_info_early(void);
49void sclp_facilities_detect(void); 48void sclp_facilities_detect(void);
50unsigned long long sclp_memory_detect(void); 49unsigned long long sclp_get_rnmax(void);
50unsigned long long sclp_get_rzm(void);
51int sclp_sdias_blk_count(void); 51int sclp_sdias_blk_count(void);
52int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); 52int sclp_sdias_copy(void *dest, int blk_num, int nr_blks);
53int sclp_chp_configure(struct chp_id chpid); 53int sclp_chp_configure(struct chp_id chpid);
diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h
index f5eebc48d98d..80747ba6ef8a 100644
--- a/include/asm-s390/setup.h
+++ b/include/asm-s390/setup.h
@@ -17,7 +17,7 @@
17#include <asm/types.h> 17#include <asm/types.h>
18 18
19#define PARMAREA 0x10400 19#define PARMAREA 0x10400
20#define MEMORY_CHUNKS 16 /* max 0x7fff */ 20#define MEMORY_CHUNKS 256
21 21
22#ifndef __ASSEMBLY__ 22#ifndef __ASSEMBLY__
23 23
@@ -38,12 +38,14 @@
38struct mem_chunk { 38struct mem_chunk {
39 unsigned long addr; 39 unsigned long addr;
40 unsigned long size; 40 unsigned long size;
41 unsigned long type; 41 int type;
42}; 42};
43 43
44extern struct mem_chunk memory_chunk[]; 44extern struct mem_chunk memory_chunk[];
45extern unsigned long real_memory_size; 45extern unsigned long real_memory_size;
46 46
47void detect_memory_layout(struct mem_chunk chunk[]);
48
47#ifdef CONFIG_S390_SWITCH_AMODE 49#ifdef CONFIG_S390_SWITCH_AMODE
48extern unsigned int switch_amode; 50extern unsigned int switch_amode;
49#else 51#else