diff options
author | Vasily Gorbik <gor@linux.ibm.com> | 2018-04-11 05:56:55 -0400 |
---|---|---|
committer | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2018-10-09 05:21:08 -0400 |
commit | 6966d604e2ec4ecf5691aea953538f63597a250d (patch) | |
tree | bb97b41e8ee7ead33cb952f690820f13d4dd8ab6 | |
parent | 17aacfbfa1ae386d3e54d12a13b88b7981e04896 (diff) |
s390/mem_detect: move tprot loop to early boot phase
Move memory detection to early boot phase. To store online memory
regions "struct mem_detect_info" has been introduced together with
for_each_mem_detect_block iterator. mem_detect_info is later converted
to memblock.
Also introduces sclp_early_get_meminfo function to get maximum physical
memory and maximum increment number.
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Reviewed-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
-rw-r--r-- | arch/s390/boot/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/boot/boot.h | 1 | ||||
-rw-r--r-- | arch/s390/boot/mem_detect.c | 133 | ||||
-rw-r--r-- | arch/s390/boot/startup.c | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/mem_detect.h | 77 | ||||
-rw-r--r-- | arch/s390/include/asm/sclp.h | 1 | ||||
-rw-r--r-- | arch/s390/include/asm/setup.h | 2 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 47 | ||||
-rw-r--r-- | arch/s390/mm/Makefile | 3 | ||||
-rw-r--r-- | arch/s390/mm/mem_detect.c | 62 | ||||
-rw-r--r-- | drivers/s390/char/sclp_early_core.c | 17 |
11 files changed, 277 insertions, 69 deletions
diff --git a/arch/s390/boot/Makefile b/arch/s390/boot/Makefile index 1b5a95b1ab09..5e2cec6e4b3e 100644 --- a/arch/s390/boot/Makefile +++ b/arch/s390/boot/Makefile | |||
@@ -27,7 +27,7 @@ endif | |||
27 | 27 | ||
28 | CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char | 28 | CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char |
29 | 29 | ||
30 | obj-y := head.o als.o startup.o ebcdic.o sclp_early_core.o mem.o | 30 | obj-y := head.o als.o startup.o mem_detect.o ebcdic.o sclp_early_core.o mem.o |
31 | targets := bzImage startup.a $(obj-y) | 31 | targets := bzImage startup.a $(obj-y) |
32 | subdir- := compressed | 32 | subdir- := compressed |
33 | 33 | ||
diff --git a/arch/s390/boot/boot.h b/arch/s390/boot/boot.h index 36c93e6cbc3f..808154b99a5d 100644 --- a/arch/s390/boot/boot.h +++ b/arch/s390/boot/boot.h | |||
@@ -3,5 +3,6 @@ | |||
3 | #define BOOT_BOOT_H | 3 | #define BOOT_BOOT_H |
4 | 4 | ||
5 | void startup_kernel(void); | 5 | void startup_kernel(void); |
6 | void detect_memory(void); | ||
6 | 7 | ||
7 | #endif /* BOOT_BOOT_H */ | 8 | #endif /* BOOT_BOOT_H */ |
diff --git a/arch/s390/boot/mem_detect.c b/arch/s390/boot/mem_detect.c new file mode 100644 index 000000000000..920e6fee75de --- /dev/null +++ b/arch/s390/boot/mem_detect.c | |||
@@ -0,0 +1,133 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | #include <linux/init.h> | ||
3 | #include <asm/sclp.h> | ||
4 | #include <asm/sections.h> | ||
5 | #include <asm/mem_detect.h> | ||
6 | #include "compressed/decompressor.h" | ||
7 | #include "boot.h" | ||
8 | |||
9 | #define CHUNK_READ_WRITE 0 | ||
10 | #define CHUNK_READ_ONLY 1 | ||
11 | |||
12 | unsigned long __bootdata(max_physmem_end); | ||
13 | struct mem_detect_info __bootdata(mem_detect); | ||
14 | |||
15 | /* up to 256 storage elements, 1020 subincrements each */ | ||
16 | #define ENTRIES_EXTENDED_MAX \ | ||
17 | (256 * (1020 / 2) * sizeof(struct mem_detect_block)) | ||
18 | |||
19 | /* | ||
20 | * To avoid corrupting old kernel memory during dump, find lowest memory | ||
21 | * chunk possible either right after the kernel end (decompressed kernel) or | ||
22 | * after initrd (if it is present and there is no hole between the kernel end | ||
23 | * and initrd) | ||
24 | */ | ||
25 | static void *mem_detect_alloc_extended(void) | ||
26 | { | ||
27 | unsigned long offset = ALIGN(mem_safe_offset(), sizeof(u64)); | ||
28 | |||
29 | if (IS_ENABLED(BLK_DEV_INITRD) && INITRD_START && INITRD_SIZE && | ||
30 | INITRD_START < offset + ENTRIES_EXTENDED_MAX) | ||
31 | offset = ALIGN(INITRD_START + INITRD_SIZE, sizeof(u64)); | ||
32 | |||
33 | return (void *)offset; | ||
34 | } | ||
35 | |||
36 | static struct mem_detect_block *__get_mem_detect_block_ptr(u32 n) | ||
37 | { | ||
38 | if (n < MEM_INLINED_ENTRIES) | ||
39 | return &mem_detect.entries[n]; | ||
40 | if (unlikely(!mem_detect.entries_extended)) | ||
41 | mem_detect.entries_extended = mem_detect_alloc_extended(); | ||
42 | return &mem_detect.entries_extended[n - MEM_INLINED_ENTRIES]; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * sequential calls to add_mem_detect_block with adjacent memory areas | ||
47 | * are merged together into single memory block. | ||
48 | */ | ||
49 | void add_mem_detect_block(u64 start, u64 end) | ||
50 | { | ||
51 | struct mem_detect_block *block; | ||
52 | |||
53 | if (mem_detect.count) { | ||
54 | block = __get_mem_detect_block_ptr(mem_detect.count - 1); | ||
55 | if (block->end == start) { | ||
56 | block->end = end; | ||
57 | return; | ||
58 | } | ||
59 | } | ||
60 | |||
61 | block = __get_mem_detect_block_ptr(mem_detect.count); | ||
62 | block->start = start; | ||
63 | block->end = end; | ||
64 | mem_detect.count++; | ||
65 | } | ||
66 | |||
67 | static unsigned long get_mem_detect_end(void) | ||
68 | { | ||
69 | if (mem_detect.count) | ||
70 | return __get_mem_detect_block_ptr(mem_detect.count - 1)->end; | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | static int tprot(unsigned long addr) | ||
75 | { | ||
76 | unsigned long pgm_addr; | ||
77 | int rc = -EFAULT; | ||
78 | psw_t old = S390_lowcore.program_new_psw; | ||
79 | |||
80 | S390_lowcore.program_new_psw.mask = __extract_psw(); | ||
81 | asm volatile( | ||
82 | " larl %[pgm_addr],1f\n" | ||
83 | " stg %[pgm_addr],%[psw_pgm_addr]\n" | ||
84 | " tprot 0(%[addr]),0\n" | ||
85 | " ipm %[rc]\n" | ||
86 | " srl %[rc],28\n" | ||
87 | "1:\n" | ||
88 | : [pgm_addr] "=&d"(pgm_addr), | ||
89 | [psw_pgm_addr] "=Q"(S390_lowcore.program_new_psw.addr), | ||
90 | [rc] "+&d"(rc) | ||
91 | : [addr] "a"(addr) | ||
92 | : "cc", "memory"); | ||
93 | S390_lowcore.program_new_psw = old; | ||
94 | return rc; | ||
95 | } | ||
96 | |||
97 | static void scan_memory(unsigned long rzm) | ||
98 | { | ||
99 | unsigned long addr, size; | ||
100 | int type; | ||
101 | |||
102 | if (!rzm) | ||
103 | rzm = 1UL << 20; | ||
104 | |||
105 | addr = 0; | ||
106 | do { | ||
107 | size = 0; | ||
108 | /* assume lowcore is writable */ | ||
109 | type = addr ? tprot(addr) : CHUNK_READ_WRITE; | ||
110 | do { | ||
111 | size += rzm; | ||
112 | if (max_physmem_end && addr + size >= max_physmem_end) | ||
113 | break; | ||
114 | } while (type == tprot(addr + size)); | ||
115 | if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) { | ||
116 | if (max_physmem_end && (addr + size > max_physmem_end)) | ||
117 | size = max_physmem_end - addr; | ||
118 | add_mem_detect_block(addr, addr + size); | ||
119 | } | ||
120 | addr += size; | ||
121 | } while (addr < max_physmem_end); | ||
122 | } | ||
123 | |||
124 | void detect_memory(void) | ||
125 | { | ||
126 | unsigned long rzm; | ||
127 | |||
128 | sclp_early_get_meminfo(&max_physmem_end, &rzm); | ||
129 | scan_memory(rzm); | ||
130 | mem_detect.info_source = MEM_DETECT_TPROT_LOOP; | ||
131 | if (!max_physmem_end) | ||
132 | max_physmem_end = get_mem_detect_end(); | ||
133 | } | ||
diff --git a/arch/s390/boot/startup.c b/arch/s390/boot/startup.c index 78651a2c26b0..b0e9f4619203 100644 --- a/arch/s390/boot/startup.c +++ b/arch/s390/boot/startup.c | |||
@@ -51,6 +51,7 @@ void startup_kernel(void) | |||
51 | 51 | ||
52 | rescue_initrd(); | 52 | rescue_initrd(); |
53 | sclp_early_read_info(); | 53 | sclp_early_read_info(); |
54 | detect_memory(); | ||
54 | if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { | 55 | if (!IS_ENABLED(CONFIG_KERNEL_UNCOMPRESSED)) { |
55 | img = decompress_kernel(); | 56 | img = decompress_kernel(); |
56 | memmove((void *)vmlinux.default_lma, img, vmlinux.image_size); | 57 | memmove((void *)vmlinux.default_lma, img, vmlinux.image_size); |
diff --git a/arch/s390/include/asm/mem_detect.h b/arch/s390/include/asm/mem_detect.h new file mode 100644 index 000000000000..8586adef1c65 --- /dev/null +++ b/arch/s390/include/asm/mem_detect.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #ifndef _ASM_S390_MEM_DETECT_H | ||
3 | #define _ASM_S390_MEM_DETECT_H | ||
4 | |||
5 | #include <linux/types.h> | ||
6 | |||
7 | enum mem_info_source { | ||
8 | MEM_DETECT_NONE = 0, | ||
9 | MEM_DETECT_TPROT_LOOP | ||
10 | }; | ||
11 | |||
12 | struct mem_detect_block { | ||
13 | u64 start; | ||
14 | u64 end; | ||
15 | }; | ||
16 | |||
17 | /* | ||
18 | * Storage element id is defined as 1 byte (up to 256 storage elements). | ||
19 | * In practise only storage element id 0 and 1 are used). | ||
20 | * According to architecture one storage element could have as much as | ||
21 | * 1020 subincrements. 255 mem_detect_blocks are embedded in mem_detect_info. | ||
22 | * If more mem_detect_blocks are required, a block of memory from already | ||
23 | * known mem_detect_block is taken (entries_extended points to it). | ||
24 | */ | ||
25 | #define MEM_INLINED_ENTRIES 255 /* (PAGE_SIZE - 16) / 16 */ | ||
26 | |||
27 | struct mem_detect_info { | ||
28 | u32 count; | ||
29 | u8 info_source; | ||
30 | struct mem_detect_block entries[MEM_INLINED_ENTRIES]; | ||
31 | struct mem_detect_block *entries_extended; | ||
32 | }; | ||
33 | extern struct mem_detect_info mem_detect; | ||
34 | |||
35 | static inline int __get_mem_detect_block(u32 n, unsigned long *start, | ||
36 | unsigned long *end) | ||
37 | { | ||
38 | if (n >= mem_detect.count) { | ||
39 | *start = 0; | ||
40 | *end = 0; | ||
41 | return -1; | ||
42 | } | ||
43 | |||
44 | if (n < MEM_INLINED_ENTRIES) { | ||
45 | *start = (unsigned long)mem_detect.entries[n].start; | ||
46 | *end = (unsigned long)mem_detect.entries[n].end; | ||
47 | } else { | ||
48 | *start = (unsigned long)mem_detect.entries_extended[n - MEM_INLINED_ENTRIES].start; | ||
49 | *end = (unsigned long)mem_detect.entries_extended[n - MEM_INLINED_ENTRIES].end; | ||
50 | } | ||
51 | return 0; | ||
52 | } | ||
53 | |||
54 | /** | ||
55 | * for_each_mem_detect_block - early online memory range iterator | ||
56 | * @i: an integer used as loop variable | ||
57 | * @p_start: ptr to unsigned long for start address of the range | ||
58 | * @p_end: ptr to unsigned long for end address of the range | ||
59 | * | ||
60 | * Walks over detected online memory ranges. | ||
61 | */ | ||
62 | #define for_each_mem_detect_block(i, p_start, p_end) \ | ||
63 | for (i = 0, __get_mem_detect_block(i, p_start, p_end); \ | ||
64 | i < mem_detect.count; \ | ||
65 | i++, __get_mem_detect_block(i, p_start, p_end)) | ||
66 | |||
67 | static inline void get_mem_detect_reserved(unsigned long *start, | ||
68 | unsigned long *size) | ||
69 | { | ||
70 | *start = (unsigned long)mem_detect.entries_extended; | ||
71 | if (mem_detect.count > MEM_INLINED_ENTRIES) | ||
72 | *size = (mem_detect.count - MEM_INLINED_ENTRIES) * sizeof(struct mem_detect_block); | ||
73 | else | ||
74 | *size = 0; | ||
75 | } | ||
76 | |||
77 | #endif | ||
diff --git a/arch/s390/include/asm/sclp.h b/arch/s390/include/asm/sclp.h index 7df57bd09aa1..c21a8b637a11 100644 --- a/arch/s390/include/asm/sclp.h +++ b/arch/s390/include/asm/sclp.h | |||
@@ -113,6 +113,7 @@ void sclp_early_printk(const char *s); | |||
113 | void sclp_early_printk_force(const char *s); | 113 | void sclp_early_printk_force(const char *s); |
114 | void __sclp_early_printk(const char *s, unsigned int len, unsigned int force); | 114 | void __sclp_early_printk(const char *s, unsigned int len, unsigned int force); |
115 | 115 | ||
116 | int sclp_early_get_meminfo(unsigned long *mem, unsigned long *rzm); | ||
116 | int _sclp_get_core_info(struct sclp_core_info *info); | 117 | int _sclp_get_core_info(struct sclp_core_info *info); |
117 | int sclp_core_configure(u8 core); | 118 | int sclp_core_configure(u8 core); |
118 | int sclp_core_deconfigure(u8 core); | 119 | int sclp_core_deconfigure(u8 core); |
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h index 1d66016f4170..522e4553373a 100644 --- a/arch/s390/include/asm/setup.h +++ b/arch/s390/include/asm/setup.h | |||
@@ -69,8 +69,6 @@ extern int memory_end_set; | |||
69 | extern unsigned long memory_end; | 69 | extern unsigned long memory_end; |
70 | extern unsigned long max_physmem_end; | 70 | extern unsigned long max_physmem_end; |
71 | 71 | ||
72 | extern void detect_memory_memblock(void); | ||
73 | |||
74 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) | 72 | #define MACHINE_IS_VM (S390_lowcore.machine_flags & MACHINE_FLAG_VM) |
75 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) | 73 | #define MACHINE_IS_KVM (S390_lowcore.machine_flags & MACHINE_FLAG_KVM) |
76 | #define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR) | 74 | #define MACHINE_IS_LPAR (S390_lowcore.machine_flags & MACHINE_FLAG_LPAR) |
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 67fa7cb8ae80..fdf9bd964dee 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -70,6 +70,7 @@ | |||
70 | #include <asm/numa.h> | 70 | #include <asm/numa.h> |
71 | #include <asm/alternative.h> | 71 | #include <asm/alternative.h> |
72 | #include <asm/nospec-branch.h> | 72 | #include <asm/nospec-branch.h> |
73 | #include <asm/mem_detect.h> | ||
73 | #include "entry.h" | 74 | #include "entry.h" |
74 | 75 | ||
75 | /* | 76 | /* |
@@ -91,7 +92,8 @@ unsigned long int_hwcap = 0; | |||
91 | 92 | ||
92 | int __initdata memory_end_set; | 93 | int __initdata memory_end_set; |
93 | unsigned long __initdata memory_end; | 94 | unsigned long __initdata memory_end; |
94 | unsigned long __initdata max_physmem_end; | 95 | unsigned long __bootdata(max_physmem_end); |
96 | struct mem_detect_info __bootdata(mem_detect); | ||
95 | 97 | ||
96 | unsigned long VMALLOC_START; | 98 | unsigned long VMALLOC_START; |
97 | EXPORT_SYMBOL(VMALLOC_START); | 99 | EXPORT_SYMBOL(VMALLOC_START); |
@@ -720,6 +722,45 @@ static void __init reserve_initrd(void) | |||
720 | #endif | 722 | #endif |
721 | } | 723 | } |
722 | 724 | ||
725 | static void __init reserve_mem_detect_info(void) | ||
726 | { | ||
727 | unsigned long start, size; | ||
728 | |||
729 | get_mem_detect_reserved(&start, &size); | ||
730 | if (size) | ||
731 | memblock_reserve(start, size); | ||
732 | } | ||
733 | |||
734 | static void __init free_mem_detect_info(void) | ||
735 | { | ||
736 | unsigned long start, size; | ||
737 | |||
738 | get_mem_detect_reserved(&start, &size); | ||
739 | if (size) | ||
740 | memblock_free(start, size); | ||
741 | } | ||
742 | |||
743 | static void __init memblock_physmem_add(phys_addr_t start, phys_addr_t size) | ||
744 | { | ||
745 | memblock_dbg("memblock_physmem_add: [%#016llx-%#016llx]\n", | ||
746 | start, start + size - 1); | ||
747 | memblock_add_range(&memblock.memory, start, size, 0, 0); | ||
748 | memblock_add_range(&memblock.physmem, start, size, 0, 0); | ||
749 | } | ||
750 | |||
751 | static void __init memblock_add_mem_detect_info(void) | ||
752 | { | ||
753 | unsigned long start, end; | ||
754 | int i; | ||
755 | |||
756 | /* keep memblock lists close to the kernel */ | ||
757 | memblock_set_bottom_up(true); | ||
758 | for_each_mem_detect_block(i, &start, &end) | ||
759 | memblock_physmem_add(start, end - start); | ||
760 | memblock_set_bottom_up(false); | ||
761 | memblock_dump_all(); | ||
762 | } | ||
763 | |||
723 | /* | 764 | /* |
724 | * Check for initrd being in usable memory | 765 | * Check for initrd being in usable memory |
725 | */ | 766 | */ |
@@ -984,11 +1025,13 @@ void __init setup_arch(char **cmdline_p) | |||
984 | reserve_oldmem(); | 1025 | reserve_oldmem(); |
985 | reserve_kernel(); | 1026 | reserve_kernel(); |
986 | reserve_initrd(); | 1027 | reserve_initrd(); |
1028 | reserve_mem_detect_info(); | ||
987 | memblock_allow_resize(); | 1029 | memblock_allow_resize(); |
988 | 1030 | ||
989 | /* Get information about *all* installed memory */ | 1031 | /* Get information about *all* installed memory */ |
990 | detect_memory_memblock(); | 1032 | memblock_add_mem_detect_info(); |
991 | 1033 | ||
1034 | free_mem_detect_info(); | ||
992 | remove_oldmem(); | 1035 | remove_oldmem(); |
993 | 1036 | ||
994 | /* | 1037 | /* |
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile index 33fe418506bc..83c83c69cab2 100644 --- a/arch/s390/mm/Makefile +++ b/arch/s390/mm/Makefile | |||
@@ -4,8 +4,7 @@ | |||
4 | # | 4 | # |
5 | 5 | ||
6 | obj-y := init.o fault.o extmem.o mmap.o vmem.o maccess.o | 6 | obj-y := init.o fault.o extmem.o mmap.o vmem.o maccess.o |
7 | obj-y += page-states.o gup.o pageattr.o mem_detect.o | 7 | obj-y += page-states.o gup.o pageattr.o pgtable.o pgalloc.o |
8 | obj-y += pgtable.o pgalloc.o | ||
9 | 8 | ||
10 | obj-$(CONFIG_CMM) += cmm.o | 9 | obj-$(CONFIG_CMM) += cmm.o |
11 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 10 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c deleted file mode 100644 index 21f6c82c8296..000000000000 --- a/arch/s390/mm/mem_detect.c +++ /dev/null | |||
@@ -1,62 +0,0 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * Copyright IBM Corp. 2008, 2009 | ||
4 | * | ||
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #include <linux/kernel.h> | ||
9 | #include <linux/memblock.h> | ||
10 | #include <linux/init.h> | ||
11 | #include <linux/debugfs.h> | ||
12 | #include <linux/seq_file.h> | ||
13 | #include <asm/ipl.h> | ||
14 | #include <asm/sclp.h> | ||
15 | #include <asm/setup.h> | ||
16 | |||
17 | #define CHUNK_READ_WRITE 0 | ||
18 | #define CHUNK_READ_ONLY 1 | ||
19 | |||
20 | static inline void memblock_physmem_add(phys_addr_t start, phys_addr_t size) | ||
21 | { | ||
22 | memblock_dbg("memblock_physmem_add: [%#016llx-%#016llx]\n", | ||
23 | start, start + size - 1); | ||
24 | memblock_add_range(&memblock.memory, start, size, 0, 0); | ||
25 | memblock_add_range(&memblock.physmem, start, size, 0, 0); | ||
26 | } | ||
27 | |||
28 | void __init detect_memory_memblock(void) | ||
29 | { | ||
30 | unsigned long memsize, rnmax, rzm, addr, size; | ||
31 | int type; | ||
32 | |||
33 | rzm = sclp.rzm; | ||
34 | rnmax = sclp.rnmax; | ||
35 | memsize = rzm * rnmax; | ||
36 | if (!rzm) | ||
37 | rzm = 1UL << 17; | ||
38 | max_physmem_end = memsize; | ||
39 | addr = 0; | ||
40 | /* keep memblock lists close to the kernel */ | ||
41 | memblock_set_bottom_up(true); | ||
42 | do { | ||
43 | size = 0; | ||
44 | /* assume lowcore is writable */ | ||
45 | type = addr ? tprot(addr) : CHUNK_READ_WRITE; | ||
46 | do { | ||
47 | size += rzm; | ||
48 | if (max_physmem_end && addr + size >= max_physmem_end) | ||
49 | break; | ||
50 | } while (type == tprot(addr + size)); | ||
51 | if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) { | ||
52 | if (max_physmem_end && (addr + size > max_physmem_end)) | ||
53 | size = max_physmem_end - addr; | ||
54 | memblock_physmem_add(addr, size); | ||
55 | } | ||
56 | addr += size; | ||
57 | } while (addr < max_physmem_end); | ||
58 | memblock_set_bottom_up(false); | ||
59 | if (!max_physmem_end) | ||
60 | max_physmem_end = memblock_end_of_DRAM(); | ||
61 | memblock_dump_all(); | ||
62 | } | ||
diff --git a/drivers/s390/char/sclp_early_core.c b/drivers/s390/char/sclp_early_core.c index bbea2154a807..4f04ba689771 100644 --- a/drivers/s390/char/sclp_early_core.c +++ b/drivers/s390/char/sclp_early_core.c | |||
@@ -270,3 +270,20 @@ int __init sclp_early_get_info(struct read_info_sccb *info) | |||
270 | *info = sclp_info_sccb; | 270 | *info = sclp_info_sccb; |
271 | return 0; | 271 | return 0; |
272 | } | 272 | } |
273 | |||
274 | int __init sclp_early_get_meminfo(unsigned long *mem, unsigned long *rzm) | ||
275 | { | ||
276 | unsigned long rnmax; | ||
277 | unsigned long rnsize; | ||
278 | struct read_info_sccb *sccb = &sclp_info_sccb; | ||
279 | |||
280 | if (!sclp_info_sccb_valid) | ||
281 | return -EIO; | ||
282 | |||
283 | rnmax = sccb->rnmax ? sccb->rnmax : sccb->rnmax2; | ||
284 | rnsize = sccb->rnsize ? sccb->rnsize : sccb->rnsize2; | ||
285 | rnsize <<= 20; | ||
286 | *mem = rnsize * rnmax; | ||
287 | *rzm = rnsize; | ||
288 | return 0; | ||
289 | } | ||