diff options
-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 |