diff options
author | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 03:59:21 -0400 |
---|---|---|
committer | Heiko Carstens <heiko.carstens@de.ibm.com> | 2008-07-14 04:02:17 -0400 |
commit | 23d1742179170b69e61ac9166248ffd64857e55a (patch) | |
tree | 5afb9b76b666f1543a6e8c42d760dfe0454e62e7 | |
parent | ef60cd13ecee0ccf2439d63013cbfc798aea2bb9 (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/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/early.c | 109 | ||||
-rw-r--r-- | arch/s390/kernel/mem_detect.c | 100 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 2 | ||||
-rw-r--r-- | drivers/s390/char/sclp_cmd.c | 33 | ||||
-rw-r--r-- | include/asm-s390/sclp.h | 4 | ||||
-rw-r--r-- | include/asm-s390/setup.h | 6 |
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 | ||
15 | obj-y := bitmap.o traps.o time.o process.o base.o early.o \ | 15 | obj-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 | ||
19 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) | 19 | obj-y += $(if $(CONFIG_64BIT),entry64.o,entry.o) |
20 | obj-y += $(if $(CONFIG_64BIT),reipl64.o,reipl.o) | 20 | obj-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 | ||
196 | static 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 | ||
219 | static inline int memory_fast_detect(void) | ||
220 | { | ||
221 | return -ENOSYS; | ||
222 | } | ||
223 | #endif | ||
224 | |||
225 | static 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 | |||
243 | static 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 | |||
289 | static __init void early_pgm_check_handler(void) | 195 | static __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 | */ |
466 | void __init startup_init(void) | 372 | void __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 | |||
12 | static 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 | |||
33 | static 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 | |||
49 | static 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 | |||
82 | void 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 | } | ||
100 | EXPORT_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; | |||
77 | unsigned long elf_hwcap = 0; | 77 | unsigned long elf_hwcap = 0; |
78 | char elf_platform[ELF_PLATFORM_SIZE]; | 78 | char elf_platform[ELF_PLATFORM_SIZE]; |
79 | 79 | ||
80 | struct mem_chunk __meminitdata memory_chunk[MEMORY_CHUNKS]; | 80 | struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS]; |
81 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ | 81 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ |
82 | static unsigned long __initdata memory_end; | 82 | static 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 | ||
70 | void __init sclp_read_info_early(void) | 70 | static 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 | ||
98 | void __init sclp_facilities_detect(void) | 98 | void __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 | |||
106 | unsigned 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 | |
114 | unsigned long long sclp_get_rnmax(void) | ||
115 | { | ||
116 | return rnmax; | ||
117 | } | ||
118 | |||
119 | unsigned 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 | */ |
125 | void __init sclp_get_ipl_info(struct sclp_ipl_info *info) | 128 | void __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 { | |||
45 | int sclp_get_cpu_info(struct sclp_cpu_info *info); | 45 | int sclp_get_cpu_info(struct sclp_cpu_info *info); |
46 | int sclp_cpu_configure(u8 cpu); | 46 | int sclp_cpu_configure(u8 cpu); |
47 | int sclp_cpu_deconfigure(u8 cpu); | 47 | int sclp_cpu_deconfigure(u8 cpu); |
48 | void sclp_read_info_early(void); | ||
49 | void sclp_facilities_detect(void); | 48 | void sclp_facilities_detect(void); |
50 | unsigned long long sclp_memory_detect(void); | 49 | unsigned long long sclp_get_rnmax(void); |
50 | unsigned long long sclp_get_rzm(void); | ||
51 | int sclp_sdias_blk_count(void); | 51 | int sclp_sdias_blk_count(void); |
52 | int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); | 52 | int sclp_sdias_copy(void *dest, int blk_num, int nr_blks); |
53 | int sclp_chp_configure(struct chp_id chpid); | 53 | int 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 @@ | |||
38 | struct mem_chunk { | 38 | struct 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 | ||
44 | extern struct mem_chunk memory_chunk[]; | 44 | extern struct mem_chunk memory_chunk[]; |
45 | extern unsigned long real_memory_size; | 45 | extern unsigned long real_memory_size; |
46 | 46 | ||
47 | void detect_memory_layout(struct mem_chunk chunk[]); | ||
48 | |||
47 | #ifdef CONFIG_S390_SWITCH_AMODE | 49 | #ifdef CONFIG_S390_SWITCH_AMODE |
48 | extern unsigned int switch_amode; | 50 | extern unsigned int switch_amode; |
49 | #else | 51 | #else |