summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVasily Gorbik <gor@linux.ibm.com>2018-04-11 05:56:55 -0400
committerMartin Schwidefsky <schwidefsky@de.ibm.com>2018-10-09 05:21:08 -0400
commit6966d604e2ec4ecf5691aea953538f63597a250d (patch)
treebb97b41e8ee7ead33cb952f690820f13d4dd8ab6
parent17aacfbfa1ae386d3e54d12a13b88b7981e04896 (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/Makefile2
-rw-r--r--arch/s390/boot/boot.h1
-rw-r--r--arch/s390/boot/mem_detect.c133
-rw-r--r--arch/s390/boot/startup.c1
-rw-r--r--arch/s390/include/asm/mem_detect.h77
-rw-r--r--arch/s390/include/asm/sclp.h1
-rw-r--r--arch/s390/include/asm/setup.h2
-rw-r--r--arch/s390/kernel/setup.c47
-rw-r--r--arch/s390/mm/Makefile3
-rw-r--r--arch/s390/mm/mem_detect.c62
-rw-r--r--drivers/s390/char/sclp_early_core.c17
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
28CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char 28CFLAGS_sclp_early_core.o += -I$(srctree)/drivers/s390/char
29 29
30obj-y := head.o als.o startup.o ebcdic.o sclp_early_core.o mem.o 30obj-y := head.o als.o startup.o mem_detect.o ebcdic.o sclp_early_core.o mem.o
31targets := bzImage startup.a $(obj-y) 31targets := bzImage startup.a $(obj-y)
32subdir- := compressed 32subdir- := 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
5void startup_kernel(void); 5void startup_kernel(void);
6void 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
12unsigned long __bootdata(max_physmem_end);
13struct 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 */
25static 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
36static 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 */
49void 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
67static 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
74static 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
97static 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
124void 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
7enum mem_info_source {
8 MEM_DETECT_NONE = 0,
9 MEM_DETECT_TPROT_LOOP
10};
11
12struct 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
27struct 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};
33extern struct mem_detect_info mem_detect;
34
35static 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
67static 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);
113void sclp_early_printk_force(const char *s); 113void sclp_early_printk_force(const char *s);
114void __sclp_early_printk(const char *s, unsigned int len, unsigned int force); 114void __sclp_early_printk(const char *s, unsigned int len, unsigned int force);
115 115
116int sclp_early_get_meminfo(unsigned long *mem, unsigned long *rzm);
116int _sclp_get_core_info(struct sclp_core_info *info); 117int _sclp_get_core_info(struct sclp_core_info *info);
117int sclp_core_configure(u8 core); 118int sclp_core_configure(u8 core);
118int sclp_core_deconfigure(u8 core); 119int 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;
69extern unsigned long memory_end; 69extern unsigned long memory_end;
70extern unsigned long max_physmem_end; 70extern unsigned long max_physmem_end;
71 71
72extern 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
92int __initdata memory_end_set; 93int __initdata memory_end_set;
93unsigned long __initdata memory_end; 94unsigned long __initdata memory_end;
94unsigned long __initdata max_physmem_end; 95unsigned long __bootdata(max_physmem_end);
96struct mem_detect_info __bootdata(mem_detect);
95 97
96unsigned long VMALLOC_START; 98unsigned long VMALLOC_START;
97EXPORT_SYMBOL(VMALLOC_START); 99EXPORT_SYMBOL(VMALLOC_START);
@@ -720,6 +722,45 @@ static void __init reserve_initrd(void)
720#endif 722#endif
721} 723}
722 724
725static 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
734static 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
743static 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
751static 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
6obj-y := init.o fault.o extmem.o mmap.o vmem.o maccess.o 6obj-y := init.o fault.o extmem.o mmap.o vmem.o maccess.o
7obj-y += page-states.o gup.o pageattr.o mem_detect.o 7obj-y += page-states.o gup.o pageattr.o pgtable.o pgalloc.o
8obj-y += pgtable.o pgalloc.o
9 8
10obj-$(CONFIG_CMM) += cmm.o 9obj-$(CONFIG_CMM) += cmm.o
11obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o 10obj-$(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
20static 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
28void __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
274int __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}