aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-05-06 15:34:53 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2013-05-06 15:34:53 -0400
commit2bf1bef0d6c3636353938dd1f183a4522957fc35 (patch)
tree3d0aae8c8454e60b0e53f456b7e94127d91f9ccf /arch/s390
parentd7ab7302f970a254997687a1cdede421a5635c68 (diff)
parent996b4a7d8f4e5dd531369396f2312b97e9400cdc (diff)
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull more s390 updates from Martin Schwidefsky: "This is the second batch of s390 patches for the 3.10 merge window. Heiko improved the memory detection, this fixes kdump for large memory sizes. Some kvm related memory management work, new ipldev/condev keywords in cio and bug fixes." * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: s390/mem_detect: remove artificial kdump memory types s390/mm: add pte invalidation notifier for kvm s390/zcrypt: ap bus rescan problem when toggle crypto adapters on/off s390/memory hotplug,sclp: get rid of per memory increment usecount s390/memory hotplug: provide memory_block_size_bytes() function s390/mem_detect: limit memory detection loop to "mem=" parameter s390/kdump,bootmem: fix bootmem allocator bitmap size s390: get rid of odd global real_memory_size s390/kvm: Change the virtual memory mapping location for Virtio devices s390/zcore: calculate real memory size using own get_mem_size function s390/mem_detect: add DAT sanity check s390/mem_detect: fix lockdep irq tracing s390/mem_detect: move memory detection code to mm folder s390/zfcpdump: exploit new cio_ignore keywords s390/cio: add condev keyword to cio_ignore s390/cio: add ipldev keyword to cio_ignore s390/uaccess: add "fallthrough" comments
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/include/asm/pgtable.h66
-rw-r--r--arch/s390/include/asm/setup.h9
-rw-r--r--arch/s390/kernel/Makefile2
-rw-r--r--arch/s390/kernel/crash_dump.c6
-rw-r--r--arch/s390/kernel/early.c1
-rw-r--r--arch/s390/kernel/mem_detect.c145
-rw-r--r--arch/s390/kernel/setup.c65
-rw-r--r--arch/s390/lib/uaccess_pt.c3
-rw-r--r--arch/s390/mm/Makefile2
-rw-r--r--arch/s390/mm/init.c11
-rw-r--r--arch/s390/mm/mem_detect.c134
-rw-r--r--arch/s390/mm/pgtable.c121
-rw-r--r--arch/s390/mm/vmem.c8
13 files changed, 356 insertions, 217 deletions
diff --git a/arch/s390/include/asm/pgtable.h b/arch/s390/include/asm/pgtable.h
index b4622915bd15..4105b8221fdd 100644
--- a/arch/s390/include/asm/pgtable.h
+++ b/arch/s390/include/asm/pgtable.h
@@ -306,6 +306,7 @@ extern unsigned long MODULES_END;
306#define RCP_HC_BIT 0x00200000UL 306#define RCP_HC_BIT 0x00200000UL
307#define RCP_GR_BIT 0x00040000UL 307#define RCP_GR_BIT 0x00040000UL
308#define RCP_GC_BIT 0x00020000UL 308#define RCP_GC_BIT 0x00020000UL
309#define RCP_IN_BIT 0x00008000UL /* IPTE notify bit */
309 310
310/* User dirty / referenced bit for KVM's migration feature */ 311/* User dirty / referenced bit for KVM's migration feature */
311#define KVM_UR_BIT 0x00008000UL 312#define KVM_UR_BIT 0x00008000UL
@@ -373,6 +374,7 @@ extern unsigned long MODULES_END;
373#define RCP_HC_BIT 0x0020000000000000UL 374#define RCP_HC_BIT 0x0020000000000000UL
374#define RCP_GR_BIT 0x0004000000000000UL 375#define RCP_GR_BIT 0x0004000000000000UL
375#define RCP_GC_BIT 0x0002000000000000UL 376#define RCP_GC_BIT 0x0002000000000000UL
377#define RCP_IN_BIT 0x0000800000000000UL /* IPTE notify bit */
376 378
377/* User dirty / referenced bit for KVM's migration feature */ 379/* User dirty / referenced bit for KVM's migration feature */
378#define KVM_UR_BIT 0x0000800000000000UL 380#define KVM_UR_BIT 0x0000800000000000UL
@@ -746,30 +748,42 @@ struct gmap {
746 748
747/** 749/**
748 * struct gmap_rmap - reverse mapping for segment table entries 750 * struct gmap_rmap - reverse mapping for segment table entries
749 * @next: pointer to the next gmap_rmap structure in the list 751 * @gmap: pointer to the gmap_struct
750 * @entry: pointer to a segment table entry 752 * @entry: pointer to a segment table entry
753 * @vmaddr: virtual address in the guest address space
751 */ 754 */
752struct gmap_rmap { 755struct gmap_rmap {
753 struct list_head list; 756 struct list_head list;
757 struct gmap *gmap;
754 unsigned long *entry; 758 unsigned long *entry;
759 unsigned long vmaddr;
755}; 760};
756 761
757/** 762/**
758 * struct gmap_pgtable - gmap information attached to a page table 763 * struct gmap_pgtable - gmap information attached to a page table
759 * @vmaddr: address of the 1MB segment in the process virtual memory 764 * @vmaddr: address of the 1MB segment in the process virtual memory
760 * @mapper: list of segment table entries maping a page table 765 * @mapper: list of segment table entries mapping a page table
761 */ 766 */
762struct gmap_pgtable { 767struct gmap_pgtable {
763 unsigned long vmaddr; 768 unsigned long vmaddr;
764 struct list_head mapper; 769 struct list_head mapper;
765}; 770};
766 771
772/**
773 * struct gmap_notifier - notify function block for page invalidation
774 * @notifier_call: address of callback function
775 */
776struct gmap_notifier {
777 struct list_head list;
778 void (*notifier_call)(struct gmap *gmap, unsigned long address);
779};
780
767struct gmap *gmap_alloc(struct mm_struct *mm); 781struct gmap *gmap_alloc(struct mm_struct *mm);
768void gmap_free(struct gmap *gmap); 782void gmap_free(struct gmap *gmap);
769void gmap_enable(struct gmap *gmap); 783void gmap_enable(struct gmap *gmap);
770void gmap_disable(struct gmap *gmap); 784void gmap_disable(struct gmap *gmap);
771int gmap_map_segment(struct gmap *gmap, unsigned long from, 785int gmap_map_segment(struct gmap *gmap, unsigned long from,
772 unsigned long to, unsigned long length); 786 unsigned long to, unsigned long len);
773int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len); 787int gmap_unmap_segment(struct gmap *gmap, unsigned long to, unsigned long len);
774unsigned long __gmap_translate(unsigned long address, struct gmap *); 788unsigned long __gmap_translate(unsigned long address, struct gmap *);
775unsigned long gmap_translate(unsigned long address, struct gmap *); 789unsigned long gmap_translate(unsigned long address, struct gmap *);
@@ -777,6 +791,24 @@ unsigned long __gmap_fault(unsigned long address, struct gmap *);
777unsigned long gmap_fault(unsigned long address, struct gmap *); 791unsigned long gmap_fault(unsigned long address, struct gmap *);
778void gmap_discard(unsigned long from, unsigned long to, struct gmap *); 792void gmap_discard(unsigned long from, unsigned long to, struct gmap *);
779 793
794void gmap_register_ipte_notifier(struct gmap_notifier *);
795void gmap_unregister_ipte_notifier(struct gmap_notifier *);
796int gmap_ipte_notify(struct gmap *, unsigned long start, unsigned long len);
797void gmap_do_ipte_notify(struct mm_struct *, unsigned long addr, pte_t *);
798
799static inline pgste_t pgste_ipte_notify(struct mm_struct *mm,
800 unsigned long addr,
801 pte_t *ptep, pgste_t pgste)
802{
803#ifdef CONFIG_PGSTE
804 if (pgste_val(pgste) & RCP_IN_BIT) {
805 pgste_val(pgste) &= ~RCP_IN_BIT;
806 gmap_do_ipte_notify(mm, addr, ptep);
807 }
808#endif
809 return pgste;
810}
811
780/* 812/*
781 * Certain architectures need to do special things when PTEs 813 * Certain architectures need to do special things when PTEs
782 * within a page table are directly modified. Thus, the following 814 * within a page table are directly modified. Thus, the following
@@ -1032,8 +1064,10 @@ static inline pte_t ptep_get_and_clear(struct mm_struct *mm,
1032 pte_t pte; 1064 pte_t pte;
1033 1065
1034 mm->context.flush_mm = 1; 1066 mm->context.flush_mm = 1;
1035 if (mm_has_pgste(mm)) 1067 if (mm_has_pgste(mm)) {
1036 pgste = pgste_get_lock(ptep); 1068 pgste = pgste_get_lock(ptep);
1069 pgste = pgste_ipte_notify(mm, address, ptep, pgste);
1070 }
1037 1071
1038 pte = *ptep; 1072 pte = *ptep;
1039 if (!mm_exclusive(mm)) 1073 if (!mm_exclusive(mm))
@@ -1052,11 +1086,14 @@ static inline pte_t ptep_modify_prot_start(struct mm_struct *mm,
1052 unsigned long address, 1086 unsigned long address,
1053 pte_t *ptep) 1087 pte_t *ptep)
1054{ 1088{
1089 pgste_t pgste;
1055 pte_t pte; 1090 pte_t pte;
1056 1091
1057 mm->context.flush_mm = 1; 1092 mm->context.flush_mm = 1;
1058 if (mm_has_pgste(mm)) 1093 if (mm_has_pgste(mm)) {
1059 pgste_get_lock(ptep); 1094 pgste = pgste_get_lock(ptep);
1095 pgste_ipte_notify(mm, address, ptep, pgste);
1096 }
1060 1097
1061 pte = *ptep; 1098 pte = *ptep;
1062 if (!mm_exclusive(mm)) 1099 if (!mm_exclusive(mm))
@@ -1082,8 +1119,10 @@ static inline pte_t ptep_clear_flush(struct vm_area_struct *vma,
1082 pgste_t pgste; 1119 pgste_t pgste;
1083 pte_t pte; 1120 pte_t pte;
1084 1121
1085 if (mm_has_pgste(vma->vm_mm)) 1122 if (mm_has_pgste(vma->vm_mm)) {
1086 pgste = pgste_get_lock(ptep); 1123 pgste = pgste_get_lock(ptep);
1124 pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste);
1125 }
1087 1126
1088 pte = *ptep; 1127 pte = *ptep;
1089 __ptep_ipte(address, ptep); 1128 __ptep_ipte(address, ptep);
@@ -1111,8 +1150,11 @@ static inline pte_t ptep_get_and_clear_full(struct mm_struct *mm,
1111 pgste_t pgste; 1150 pgste_t pgste;
1112 pte_t pte; 1151 pte_t pte;
1113 1152
1114 if (mm_has_pgste(mm)) 1153 if (mm_has_pgste(mm)) {
1115 pgste = pgste_get_lock(ptep); 1154 pgste = pgste_get_lock(ptep);
1155 if (!full)
1156 pgste = pgste_ipte_notify(mm, address, ptep, pgste);
1157 }
1116 1158
1117 pte = *ptep; 1159 pte = *ptep;
1118 if (!full) 1160 if (!full)
@@ -1135,8 +1177,10 @@ static inline pte_t ptep_set_wrprotect(struct mm_struct *mm,
1135 1177
1136 if (pte_write(pte)) { 1178 if (pte_write(pte)) {
1137 mm->context.flush_mm = 1; 1179 mm->context.flush_mm = 1;
1138 if (mm_has_pgste(mm)) 1180 if (mm_has_pgste(mm)) {
1139 pgste = pgste_get_lock(ptep); 1181 pgste = pgste_get_lock(ptep);
1182 pgste = pgste_ipte_notify(mm, address, ptep, pgste);
1183 }
1140 1184
1141 if (!mm_exclusive(mm)) 1185 if (!mm_exclusive(mm))
1142 __ptep_ipte(address, ptep); 1186 __ptep_ipte(address, ptep);
@@ -1160,8 +1204,10 @@ static inline int ptep_set_access_flags(struct vm_area_struct *vma,
1160 1204
1161 if (pte_same(*ptep, entry)) 1205 if (pte_same(*ptep, entry))
1162 return 0; 1206 return 0;
1163 if (mm_has_pgste(vma->vm_mm)) 1207 if (mm_has_pgste(vma->vm_mm)) {
1164 pgste = pgste_get_lock(ptep); 1208 pgste = pgste_get_lock(ptep);
1209 pgste = pgste_ipte_notify(vma->vm_mm, address, ptep, pgste);
1210 }
1165 1211
1166 __ptep_ipte(address, ptep); 1212 __ptep_ipte(address, ptep);
1167 1213
diff --git a/arch/s390/include/asm/setup.h b/arch/s390/include/asm/setup.h
index ff67d730c00c..59880dbaf360 100644
--- a/arch/s390/include/asm/setup.h
+++ b/arch/s390/include/asm/setup.h
@@ -33,8 +33,6 @@
33 33
34#define CHUNK_READ_WRITE 0 34#define CHUNK_READ_WRITE 0
35#define CHUNK_READ_ONLY 1 35#define CHUNK_READ_ONLY 1
36#define CHUNK_OLDMEM 4
37#define CHUNK_CRASHK 5
38 36
39struct mem_chunk { 37struct mem_chunk {
40 unsigned long addr; 38 unsigned long addr;
@@ -43,13 +41,12 @@ struct mem_chunk {
43}; 41};
44 42
45extern struct mem_chunk memory_chunk[]; 43extern struct mem_chunk memory_chunk[];
46extern unsigned long real_memory_size;
47extern int memory_end_set; 44extern int memory_end_set;
48extern unsigned long memory_end; 45extern unsigned long memory_end;
49 46
50void detect_memory_layout(struct mem_chunk chunk[]); 47void detect_memory_layout(struct mem_chunk chunk[], unsigned long maxsize);
51void create_mem_hole(struct mem_chunk memory_chunk[], unsigned long addr, 48void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
52 unsigned long size, int type); 49 unsigned long size);
53 50
54#define PRIMARY_SPACE_MODE 0 51#define PRIMARY_SPACE_MODE 0
55#define ACCESS_REGISTER_MODE 1 52#define ACCESS_REGISTER_MODE 1
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile
index 1386fcaf4ef6..4bb2a4656163 100644
--- a/arch/s390/kernel/Makefile
+++ b/arch/s390/kernel/Makefile
@@ -30,7 +30,7 @@ CFLAGS_sysinfo.o += -Iinclude/math-emu -Iarch/s390/math-emu -w
30 30
31obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o 31obj-y := bitmap.o traps.o time.o process.o base.o early.o setup.o vtime.o
32obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o 32obj-y += processor.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o nmi.o
33obj-y += debug.o irq.o ipl.o dis.o diag.o mem_detect.o sclp.o vdso.o 33obj-y += debug.o irq.o ipl.o dis.o diag.o sclp.o vdso.o
34obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o 34obj-y += sysinfo.o jump_label.o lgr.o os_info.o machine_kexec.o pgm_check.o
35obj-y += dumpstack.o 35obj-y += dumpstack.o
36 36
diff --git a/arch/s390/kernel/crash_dump.c b/arch/s390/kernel/crash_dump.c
index fb8d8781a011..f703d91bf720 100644
--- a/arch/s390/kernel/crash_dump.c
+++ b/arch/s390/kernel/crash_dump.c
@@ -88,8 +88,8 @@ static struct mem_chunk *get_memory_layout(void)
88 struct mem_chunk *chunk_array; 88 struct mem_chunk *chunk_array;
89 89
90 chunk_array = kzalloc_panic(MEMORY_CHUNKS * sizeof(struct mem_chunk)); 90 chunk_array = kzalloc_panic(MEMORY_CHUNKS * sizeof(struct mem_chunk));
91 detect_memory_layout(chunk_array); 91 detect_memory_layout(chunk_array, 0);
92 create_mem_hole(chunk_array, OLDMEM_BASE, OLDMEM_SIZE, CHUNK_CRASHK); 92 create_mem_hole(chunk_array, OLDMEM_BASE, OLDMEM_SIZE);
93 return chunk_array; 93 return chunk_array;
94} 94}
95 95
@@ -344,7 +344,7 @@ static int loads_init(Elf64_Phdr *phdr, u64 loads_offset)
344 for (i = 0; i < MEMORY_CHUNKS; i++) { 344 for (i = 0; i < MEMORY_CHUNKS; i++) {
345 mem_chunk = &chunk_array[i]; 345 mem_chunk = &chunk_array[i];
346 if (mem_chunk->size == 0) 346 if (mem_chunk->size == 0)
347 break; 347 continue;
348 if (chunk_array[i].type != CHUNK_READ_WRITE && 348 if (chunk_array[i].type != CHUNK_READ_WRITE &&
349 chunk_array[i].type != CHUNK_READ_ONLY) 349 chunk_array[i].type != CHUNK_READ_ONLY)
350 continue; 350 continue;
diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index bda011e2f8ae..dc8770d7173c 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -482,7 +482,6 @@ void __init startup_init(void)
482 detect_machine_facilities(); 482 detect_machine_facilities();
483 setup_topology(); 483 setup_topology();
484 sclp_facilities_detect(); 484 sclp_facilities_detect();
485 detect_memory_layout(memory_chunk);
486#ifdef CONFIG_DYNAMIC_FTRACE 485#ifdef CONFIG_DYNAMIC_FTRACE
487 S390_lowcore.ftrace_func = (unsigned long)ftrace_caller; 486 S390_lowcore.ftrace_func = (unsigned long)ftrace_caller;
488#endif 487#endif
diff --git a/arch/s390/kernel/mem_detect.c b/arch/s390/kernel/mem_detect.c
deleted file mode 100644
index 22d502e885ed..000000000000
--- a/arch/s390/kernel/mem_detect.c
+++ /dev/null
@@ -1,145 +0,0 @@
1/*
2 * Copyright IBM Corp. 2008, 2009
3 *
4 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
5 */
6
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <asm/ipl.h>
10#include <asm/sclp.h>
11#include <asm/setup.h>
12
13#define ADDR2G (1ULL << 31)
14
15static void find_memory_chunks(struct mem_chunk chunk[])
16{
17 unsigned long long memsize, rnmax, rzm;
18 unsigned long addr = 0, size;
19 int i = 0, type;
20
21 rzm = sclp_get_rzm();
22 rnmax = sclp_get_rnmax();
23 memsize = rzm * rnmax;
24 if (!rzm)
25 rzm = 1ULL << 17;
26 if (sizeof(long) == 4) {
27 rzm = min(ADDR2G, rzm);
28 memsize = memsize ? min(ADDR2G, memsize) : ADDR2G;
29 }
30 do {
31 size = 0;
32 type = tprot(addr);
33 do {
34 size += rzm;
35 if (memsize && addr + size >= memsize)
36 break;
37 } while (type == tprot(addr + size));
38 if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) {
39 chunk[i].addr = addr;
40 chunk[i].size = size;
41 chunk[i].type = type;
42 i++;
43 }
44 addr += size;
45 } while (addr < memsize && i < MEMORY_CHUNKS);
46}
47
48void detect_memory_layout(struct mem_chunk chunk[])
49{
50 unsigned long flags, cr0;
51
52 memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk));
53 /* Disable IRQs, DAT and low address protection so tprot does the
54 * right thing and we don't get scheduled away with low address
55 * protection disabled.
56 */
57 flags = __arch_local_irq_stnsm(0xf8);
58 __ctl_store(cr0, 0, 0);
59 __ctl_clear_bit(0, 28);
60 find_memory_chunks(chunk);
61 __ctl_load(cr0, 0, 0);
62 arch_local_irq_restore(flags);
63}
64EXPORT_SYMBOL(detect_memory_layout);
65
66/*
67 * Move memory chunks array from index "from" to index "to"
68 */
69static void mem_chunk_move(struct mem_chunk chunk[], int to, int from)
70{
71 int cnt = MEMORY_CHUNKS - to;
72
73 memmove(&chunk[to], &chunk[from], cnt * sizeof(struct mem_chunk));
74}
75
76/*
77 * Initialize memory chunk
78 */
79static void mem_chunk_init(struct mem_chunk *chunk, unsigned long addr,
80 unsigned long size, int type)
81{
82 chunk->type = type;
83 chunk->addr = addr;
84 chunk->size = size;
85}
86
87/*
88 * Create memory hole with given address, size, and type
89 */
90void create_mem_hole(struct mem_chunk chunk[], unsigned long addr,
91 unsigned long size, int type)
92{
93 unsigned long lh_start, lh_end, lh_size, ch_start, ch_end, ch_size;
94 int i, ch_type;
95
96 for (i = 0; i < MEMORY_CHUNKS; i++) {
97 if (chunk[i].size == 0)
98 continue;
99
100 /* Define chunk properties */
101 ch_start = chunk[i].addr;
102 ch_size = chunk[i].size;
103 ch_end = ch_start + ch_size - 1;
104 ch_type = chunk[i].type;
105
106 /* Is memory chunk hit by memory hole? */
107 if (addr + size <= ch_start)
108 continue; /* No: memory hole in front of chunk */
109 if (addr > ch_end)
110 continue; /* No: memory hole after chunk */
111
112 /* Yes: Define local hole properties */
113 lh_start = max(addr, chunk[i].addr);
114 lh_end = min(addr + size - 1, ch_end);
115 lh_size = lh_end - lh_start + 1;
116
117 if (lh_start == ch_start && lh_end == ch_end) {
118 /* Hole covers complete memory chunk */
119 mem_chunk_init(&chunk[i], lh_start, lh_size, type);
120 } else if (lh_end == ch_end) {
121 /* Hole starts in memory chunk and convers chunk end */
122 mem_chunk_move(chunk, i + 1, i);
123 mem_chunk_init(&chunk[i], ch_start, ch_size - lh_size,
124 ch_type);
125 mem_chunk_init(&chunk[i + 1], lh_start, lh_size, type);
126 i += 1;
127 } else if (lh_start == ch_start) {
128 /* Hole ends in memory chunk */
129 mem_chunk_move(chunk, i + 1, i);
130 mem_chunk_init(&chunk[i], lh_start, lh_size, type);
131 mem_chunk_init(&chunk[i + 1], lh_end + 1,
132 ch_size - lh_size, ch_type);
133 break;
134 } else {
135 /* Hole splits memory chunk */
136 mem_chunk_move(chunk, i + 2, i);
137 mem_chunk_init(&chunk[i], ch_start,
138 lh_start - ch_start, ch_type);
139 mem_chunk_init(&chunk[i + 1], lh_start, lh_size, type);
140 mem_chunk_init(&chunk[i + 2], lh_end + 1,
141 ch_end - lh_end, ch_type);
142 break;
143 }
144 }
145}
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 0f419c5765c8..0a49095104c9 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -226,25 +226,17 @@ static void __init conmode_default(void)
226} 226}
227 227
228#ifdef CONFIG_ZFCPDUMP 228#ifdef CONFIG_ZFCPDUMP
229static void __init setup_zfcpdump(unsigned int console_devno) 229static void __init setup_zfcpdump(void)
230{ 230{
231 static char str[41];
232
233 if (ipl_info.type != IPL_TYPE_FCP_DUMP) 231 if (ipl_info.type != IPL_TYPE_FCP_DUMP)
234 return; 232 return;
235 if (OLDMEM_BASE) 233 if (OLDMEM_BASE)
236 return; 234 return;
237 if (console_devno != -1) 235 strcat(boot_command_line, " cio_ignore=all,!ipldev,!condev");
238 sprintf(str, " cio_ignore=all,!0.0.%04x,!0.0.%04x",
239 ipl_info.data.fcp.dev_id.devno, console_devno);
240 else
241 sprintf(str, " cio_ignore=all,!0.0.%04x",
242 ipl_info.data.fcp.dev_id.devno);
243 strcat(boot_command_line, str);
244 console_loglevel = 2; 236 console_loglevel = 2;
245} 237}
246#else 238#else
247static inline void setup_zfcpdump(unsigned int console_devno) {} 239static inline void setup_zfcpdump(void) {}
248#endif /* CONFIG_ZFCPDUMP */ 240#endif /* CONFIG_ZFCPDUMP */
249 241
250 /* 242 /*
@@ -471,14 +463,10 @@ static void __init setup_resources(void)
471 for (i = 0; i < MEMORY_CHUNKS; i++) { 463 for (i = 0; i < MEMORY_CHUNKS; i++) {
472 if (!memory_chunk[i].size) 464 if (!memory_chunk[i].size)
473 continue; 465 continue;
474 if (memory_chunk[i].type == CHUNK_OLDMEM ||
475 memory_chunk[i].type == CHUNK_CRASHK)
476 continue;
477 res = alloc_bootmem_low(sizeof(*res)); 466 res = alloc_bootmem_low(sizeof(*res));
478 res->flags = IORESOURCE_BUSY | IORESOURCE_MEM; 467 res->flags = IORESOURCE_BUSY | IORESOURCE_MEM;
479 switch (memory_chunk[i].type) { 468 switch (memory_chunk[i].type) {
480 case CHUNK_READ_WRITE: 469 case CHUNK_READ_WRITE:
481 case CHUNK_CRASHK:
482 res->name = "System RAM"; 470 res->name = "System RAM";
483 break; 471 break;
484 case CHUNK_READ_ONLY: 472 case CHUNK_READ_ONLY:
@@ -510,12 +498,10 @@ static void __init setup_resources(void)
510 } 498 }
511} 499}
512 500
513unsigned long real_memory_size;
514EXPORT_SYMBOL_GPL(real_memory_size);
515
516static void __init setup_memory_end(void) 501static void __init setup_memory_end(void)
517{ 502{
518 unsigned long vmax, vmalloc_size, tmp; 503 unsigned long vmax, vmalloc_size, tmp;
504 unsigned long real_memory_size = 0;
519 int i; 505 int i;
520 506
521 507
@@ -525,7 +511,6 @@ static void __init setup_memory_end(void)
525 memory_end_set = 1; 511 memory_end_set = 1;
526 } 512 }
527#endif 513#endif
528 real_memory_size = 0;
529 memory_end &= PAGE_MASK; 514 memory_end &= PAGE_MASK;
530 515
531 /* 516 /*
@@ -538,6 +523,8 @@ static void __init setup_memory_end(void)
538 unsigned long align; 523 unsigned long align;
539 524
540 chunk = &memory_chunk[i]; 525 chunk = &memory_chunk[i];
526 if (!chunk->size)
527 continue;
541 align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1); 528 align = 1UL << (MAX_ORDER + PAGE_SHIFT - 1);
542 start = (chunk->addr + align - 1) & ~(align - 1); 529 start = (chunk->addr + align - 1) & ~(align - 1);
543 end = (chunk->addr + chunk->size) & ~(align - 1); 530 end = (chunk->addr + chunk->size) & ~(align - 1);
@@ -588,6 +575,8 @@ static void __init setup_memory_end(void)
588 for (i = 0; i < MEMORY_CHUNKS; i++) { 575 for (i = 0; i < MEMORY_CHUNKS; i++) {
589 struct mem_chunk *chunk = &memory_chunk[i]; 576 struct mem_chunk *chunk = &memory_chunk[i];
590 577
578 if (!chunk->size)
579 continue;
591 if (chunk->addr >= memory_end) { 580 if (chunk->addr >= memory_end) {
592 memset(chunk, 0, sizeof(*chunk)); 581 memset(chunk, 0, sizeof(*chunk));
593 continue; 582 continue;
@@ -688,15 +677,6 @@ static int __init verify_crash_base(unsigned long crash_base,
688} 677}
689 678
690/* 679/*
691 * Reserve kdump memory by creating a memory hole in the mem_chunk array
692 */
693static void __init reserve_kdump_bootmem(unsigned long addr, unsigned long size,
694 int type)
695{
696 create_mem_hole(memory_chunk, addr, size, type);
697}
698
699/*
700 * When kdump is enabled, we have to ensure that no memory from 680 * When kdump is enabled, we have to ensure that no memory from
701 * the area [0 - crashkernel memory size] and 681 * the area [0 - crashkernel memory size] and
702 * [crashk_res.start - crashk_res.end] is set offline. 682 * [crashk_res.start - crashk_res.end] is set offline.
@@ -727,16 +707,22 @@ static struct notifier_block kdump_mem_nb = {
727static void reserve_oldmem(void) 707static void reserve_oldmem(void)
728{ 708{
729#ifdef CONFIG_CRASH_DUMP 709#ifdef CONFIG_CRASH_DUMP
710 unsigned long real_size = 0;
711 int i;
712
730 if (!OLDMEM_BASE) 713 if (!OLDMEM_BASE)
731 return; 714 return;
715 for (i = 0; i < MEMORY_CHUNKS; i++) {
716 struct mem_chunk *chunk = &memory_chunk[i];
732 717
733 reserve_kdump_bootmem(OLDMEM_BASE, OLDMEM_SIZE, CHUNK_OLDMEM); 718 real_size = max(real_size, chunk->addr + chunk->size);
734 reserve_kdump_bootmem(OLDMEM_SIZE, memory_end - OLDMEM_SIZE, 719 }
735 CHUNK_OLDMEM); 720 create_mem_hole(memory_chunk, OLDMEM_BASE, OLDMEM_SIZE);
736 if (OLDMEM_BASE + OLDMEM_SIZE == real_memory_size) 721 create_mem_hole(memory_chunk, OLDMEM_SIZE, real_size - OLDMEM_SIZE);
722 if (OLDMEM_BASE + OLDMEM_SIZE == real_size)
737 saved_max_pfn = PFN_DOWN(OLDMEM_BASE) - 1; 723 saved_max_pfn = PFN_DOWN(OLDMEM_BASE) - 1;
738 else 724 else
739 saved_max_pfn = PFN_DOWN(real_memory_size) - 1; 725 saved_max_pfn = PFN_DOWN(real_size) - 1;
740#endif 726#endif
741} 727}
742 728
@@ -775,7 +761,7 @@ static void __init reserve_crashkernel(void)
775 crashk_res.start = crash_base; 761 crashk_res.start = crash_base;
776 crashk_res.end = crash_base + crash_size - 1; 762 crashk_res.end = crash_base + crash_size - 1;
777 insert_resource(&iomem_resource, &crashk_res); 763 insert_resource(&iomem_resource, &crashk_res);
778 reserve_kdump_bootmem(crash_base, crash_size, CHUNK_CRASHK); 764 create_mem_hole(memory_chunk, crash_base, crash_size);
779 pr_info("Reserving %lluMB of memory at %lluMB " 765 pr_info("Reserving %lluMB of memory at %lluMB "
780 "for crashkernel (System RAM: %luMB)\n", 766 "for crashkernel (System RAM: %luMB)\n",
781 crash_size >> 20, crash_base >> 20, memory_end >> 20); 767 crash_size >> 20, crash_base >> 20, memory_end >> 20);
@@ -847,11 +833,10 @@ static void __init setup_memory(void)
847 * Register RAM areas with the bootmem allocator. 833 * Register RAM areas with the bootmem allocator.
848 */ 834 */
849 835
850 for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { 836 for (i = 0; i < MEMORY_CHUNKS; i++) {
851 unsigned long start_chunk, end_chunk, pfn; 837 unsigned long start_chunk, end_chunk, pfn;
852 838
853 if (memory_chunk[i].type != CHUNK_READ_WRITE && 839 if (!memory_chunk[i].size)
854 memory_chunk[i].type != CHUNK_CRASHK)
855 continue; 840 continue;
856 start_chunk = PFN_DOWN(memory_chunk[i].addr); 841 start_chunk = PFN_DOWN(memory_chunk[i].addr);
857 end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size); 842 end_chunk = start_chunk + PFN_DOWN(memory_chunk[i].size);
@@ -1067,12 +1052,12 @@ void __init setup_arch(char **cmdline_p)
1067 memcpy(&uaccess, &uaccess_std, sizeof(uaccess)); 1052 memcpy(&uaccess, &uaccess_std, sizeof(uaccess));
1068 1053
1069 parse_early_param(); 1054 parse_early_param();
1070 1055 detect_memory_layout(memory_chunk, memory_end);
1071 os_info_init(); 1056 os_info_init();
1072 setup_ipl(); 1057 setup_ipl();
1058 reserve_oldmem();
1073 setup_memory_end(); 1059 setup_memory_end();
1074 setup_addressing_mode(); 1060 setup_addressing_mode();
1075 reserve_oldmem();
1076 reserve_crashkernel(); 1061 reserve_crashkernel();
1077 setup_memory(); 1062 setup_memory();
1078 setup_resources(); 1063 setup_resources();
@@ -1097,5 +1082,5 @@ void __init setup_arch(char **cmdline_p)
1097 set_preferred_console(); 1082 set_preferred_console();
1098 1083
1099 /* Setup zfcpdump support */ 1084 /* Setup zfcpdump support */
1100 setup_zfcpdump(console_devno); 1085 setup_zfcpdump();
1101} 1086}
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c
index 466fb3383960..50ea137a2d3c 100644
--- a/arch/s390/lib/uaccess_pt.c
+++ b/arch/s390/lib/uaccess_pt.c
@@ -89,16 +89,19 @@ static unsigned long follow_table(struct mm_struct *mm,
89 if (unlikely(*table & _REGION_ENTRY_INV)) 89 if (unlikely(*table & _REGION_ENTRY_INV))
90 return -0x39UL; 90 return -0x39UL;
91 table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); 91 table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
92 /* fallthrough */
92 case _ASCE_TYPE_REGION2: 93 case _ASCE_TYPE_REGION2:
93 table = table + ((address >> 42) & 0x7ff); 94 table = table + ((address >> 42) & 0x7ff);
94 if (unlikely(*table & _REGION_ENTRY_INV)) 95 if (unlikely(*table & _REGION_ENTRY_INV))
95 return -0x3aUL; 96 return -0x3aUL;
96 table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); 97 table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
98 /* fallthrough */
97 case _ASCE_TYPE_REGION3: 99 case _ASCE_TYPE_REGION3:
98 table = table + ((address >> 31) & 0x7ff); 100 table = table + ((address >> 31) & 0x7ff);
99 if (unlikely(*table & _REGION_ENTRY_INV)) 101 if (unlikely(*table & _REGION_ENTRY_INV))
100 return -0x3bUL; 102 return -0x3bUL;
101 table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN); 103 table = (unsigned long *)(*table & _REGION_ENTRY_ORIGIN);
104 /* fallthrough */
102 case _ASCE_TYPE_SEGMENT: 105 case _ASCE_TYPE_SEGMENT:
103 table = table + ((address >> 20) & 0x7ff); 106 table = table + ((address >> 20) & 0x7ff);
104 if (unlikely(*table & _SEGMENT_ENTRY_INV)) 107 if (unlikely(*table & _SEGMENT_ENTRY_INV))
diff --git a/arch/s390/mm/Makefile b/arch/s390/mm/Makefile
index 640bea12303c..839592ca265c 100644
--- a/arch/s390/mm/Makefile
+++ b/arch/s390/mm/Makefile
@@ -3,7 +3,7 @@
3# 3#
4 4
5obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o 5obj-y := init.o fault.o extmem.o mmap.o vmem.o pgtable.o maccess.o
6obj-y += page-states.o gup.o extable.o pageattr.o 6obj-y += page-states.o gup.o extable.o pageattr.o mem_detect.o
7 7
8obj-$(CONFIG_CMM) += cmm.o 8obj-$(CONFIG_CMM) += cmm.o
9obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o 9obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
diff --git a/arch/s390/mm/init.c b/arch/s390/mm/init.c
index 0b09b2342302..89ebae4008f2 100644
--- a/arch/s390/mm/init.c
+++ b/arch/s390/mm/init.c
@@ -21,6 +21,7 @@
21#include <linux/init.h> 21#include <linux/init.h>
22#include <linux/pagemap.h> 22#include <linux/pagemap.h>
23#include <linux/bootmem.h> 23#include <linux/bootmem.h>
24#include <linux/memory.h>
24#include <linux/pfn.h> 25#include <linux/pfn.h>
25#include <linux/poison.h> 26#include <linux/poison.h>
26#include <linux/initrd.h> 27#include <linux/initrd.h>
@@ -36,6 +37,7 @@
36#include <asm/tlbflush.h> 37#include <asm/tlbflush.h>
37#include <asm/sections.h> 38#include <asm/sections.h>
38#include <asm/ctl_reg.h> 39#include <asm/ctl_reg.h>
40#include <asm/sclp.h>
39 41
40pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE))); 42pgd_t swapper_pg_dir[PTRS_PER_PGD] __attribute__((__aligned__(PAGE_SIZE)));
41 43
@@ -214,6 +216,15 @@ int arch_add_memory(int nid, u64 start, u64 size)
214 return rc; 216 return rc;
215} 217}
216 218
219unsigned long memory_block_size_bytes(void)
220{
221 /*
222 * Make sure the memory block size is always greater
223 * or equal than the memory increment size.
224 */
225 return max_t(unsigned long, MIN_MEMORY_BLOCK_SIZE, sclp_get_rzm());
226}
227
217#ifdef CONFIG_MEMORY_HOTREMOVE 228#ifdef CONFIG_MEMORY_HOTREMOVE
218int arch_remove_memory(u64 start, u64 size) 229int arch_remove_memory(u64 start, u64 size)
219{ 230{
diff --git a/arch/s390/mm/mem_detect.c b/arch/s390/mm/mem_detect.c
new file mode 100644
index 000000000000..3cbd3b8bf311
--- /dev/null
+++ b/arch/s390/mm/mem_detect.c
@@ -0,0 +1,134 @@
1/*
2 * Copyright IBM Corp. 2008, 2009
3 *
4 * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com>
5 */
6
7#include <linux/kernel.h>
8#include <linux/module.h>
9#include <asm/ipl.h>
10#include <asm/sclp.h>
11#include <asm/setup.h>
12
13#define ADDR2G (1ULL << 31)
14
15static void find_memory_chunks(struct mem_chunk chunk[], unsigned long maxsize)
16{
17 unsigned long long memsize, rnmax, rzm;
18 unsigned long addr = 0, size;
19 int i = 0, type;
20
21 rzm = sclp_get_rzm();
22 rnmax = sclp_get_rnmax();
23 memsize = rzm * rnmax;
24 if (!rzm)
25 rzm = 1ULL << 17;
26 if (sizeof(long) == 4) {
27 rzm = min(ADDR2G, rzm);
28 memsize = memsize ? min(ADDR2G, memsize) : ADDR2G;
29 }
30 if (maxsize)
31 memsize = memsize ? min((unsigned long)memsize, maxsize) : maxsize;
32 do {
33 size = 0;
34 type = tprot(addr);
35 do {
36 size += rzm;
37 if (memsize && addr + size >= memsize)
38 break;
39 } while (type == tprot(addr + size));
40 if (type == CHUNK_READ_WRITE || type == CHUNK_READ_ONLY) {
41 if (memsize && (addr + size > memsize))
42 size = memsize - addr;
43 chunk[i].addr = addr;
44 chunk[i].size = size;
45 chunk[i].type = type;
46 i++;
47 }
48 addr += size;
49 } while (addr < memsize && i < MEMORY_CHUNKS);
50}
51
52/**
53 * detect_memory_layout - fill mem_chunk array with memory layout data
54 * @chunk: mem_chunk array to be filled
55 * @maxsize: maximum address where memory detection should stop
56 *
57 * Fills the passed in memory chunk array with the memory layout of the
58 * machine. The array must have a size of at least MEMORY_CHUNKS and will
59 * be fully initialized afterwards.
60 * If the maxsize paramater has a value > 0 memory detection will stop at
61 * that address. It is guaranteed that all chunks have an ending address
62 * that is smaller than maxsize.
63 * If maxsize is 0 all memory will be detected.
64 */
65void detect_memory_layout(struct mem_chunk chunk[], unsigned long maxsize)
66{
67 unsigned long flags, flags_dat, cr0;
68
69 memset(chunk, 0, MEMORY_CHUNKS * sizeof(struct mem_chunk));
70 /*
71 * Disable IRQs, DAT and low address protection so tprot does the
72 * right thing and we don't get scheduled away with low address
73 * protection disabled.
74 */
75 local_irq_save(flags);
76 flags_dat = __arch_local_irq_stnsm(0xfb);
77 /*
78 * In case DAT was enabled, make sure chunk doesn't reside in vmalloc
79 * space. We have disabled DAT and any access to vmalloc area will
80 * cause an exception.
81 * If DAT was disabled we are called from early ipl code.
82 */
83 if (test_bit(5, &flags_dat)) {
84 if (WARN_ON_ONCE(is_vmalloc_or_module_addr(chunk)))
85 goto out;
86 }
87 __ctl_store(cr0, 0, 0);
88 __ctl_clear_bit(0, 28);
89 find_memory_chunks(chunk, maxsize);
90 __ctl_load(cr0, 0, 0);
91out:
92 __arch_local_irq_ssm(flags_dat);
93 local_irq_restore(flags);
94}
95EXPORT_SYMBOL(detect_memory_layout);
96
97/*
98 * Create memory hole with given address and size.
99 */
100void create_mem_hole(struct mem_chunk mem_chunk[], unsigned long addr,
101 unsigned long size)
102{
103 int i;
104
105 for (i = 0; i < MEMORY_CHUNKS; i++) {
106 struct mem_chunk *chunk = &mem_chunk[i];
107
108 if (chunk->size == 0)
109 continue;
110 if (addr > chunk->addr + chunk->size)
111 continue;
112 if (addr + size <= chunk->addr)
113 continue;
114 /* Split */
115 if ((addr > chunk->addr) &&
116 (addr + size < chunk->addr + chunk->size)) {
117 struct mem_chunk *new = chunk + 1;
118
119 memmove(new, chunk, (MEMORY_CHUNKS-i-1) * sizeof(*new));
120 new->addr = addr + size;
121 new->size = chunk->addr + chunk->size - new->addr;
122 chunk->size = addr - chunk->addr;
123 continue;
124 } else if ((addr <= chunk->addr) &&
125 (addr + size >= chunk->addr + chunk->size)) {
126 memset(chunk, 0 , sizeof(*chunk));
127 } else if (addr + size < chunk->addr + chunk->size) {
128 chunk->size = chunk->addr + chunk->size - addr - size;
129 chunk->addr = addr + size;
130 } else if (addr > chunk->addr) {
131 chunk->size = addr - chunk->addr;
132 }
133 }
134}
diff --git a/arch/s390/mm/pgtable.c b/arch/s390/mm/pgtable.c
index bd954e96f51c..7805ddca833d 100644
--- a/arch/s390/mm/pgtable.c
+++ b/arch/s390/mm/pgtable.c
@@ -454,9 +454,8 @@ unsigned long gmap_translate(unsigned long address, struct gmap *gmap)
454} 454}
455EXPORT_SYMBOL_GPL(gmap_translate); 455EXPORT_SYMBOL_GPL(gmap_translate);
456 456
457static int gmap_connect_pgtable(unsigned long segment, 457static int gmap_connect_pgtable(unsigned long address, unsigned long segment,
458 unsigned long *segment_ptr, 458 unsigned long *segment_ptr, struct gmap *gmap)
459 struct gmap *gmap)
460{ 459{
461 unsigned long vmaddr; 460 unsigned long vmaddr;
462 struct vm_area_struct *vma; 461 struct vm_area_struct *vma;
@@ -491,7 +490,9 @@ static int gmap_connect_pgtable(unsigned long segment,
491 /* Link gmap segment table entry location to page table. */ 490 /* Link gmap segment table entry location to page table. */
492 page = pmd_page(*pmd); 491 page = pmd_page(*pmd);
493 mp = (struct gmap_pgtable *) page->index; 492 mp = (struct gmap_pgtable *) page->index;
493 rmap->gmap = gmap;
494 rmap->entry = segment_ptr; 494 rmap->entry = segment_ptr;
495 rmap->vmaddr = address;
495 spin_lock(&mm->page_table_lock); 496 spin_lock(&mm->page_table_lock);
496 if (*segment_ptr == segment) { 497 if (*segment_ptr == segment) {
497 list_add(&rmap->list, &mp->mapper); 498 list_add(&rmap->list, &mp->mapper);
@@ -553,7 +554,7 @@ unsigned long __gmap_fault(unsigned long address, struct gmap *gmap)
553 if (!(segment & _SEGMENT_ENTRY_RO)) 554 if (!(segment & _SEGMENT_ENTRY_RO))
554 /* Nothing mapped in the gmap address space. */ 555 /* Nothing mapped in the gmap address space. */
555 break; 556 break;
556 rc = gmap_connect_pgtable(segment, segment_ptr, gmap); 557 rc = gmap_connect_pgtable(address, segment, segment_ptr, gmap);
557 if (rc) 558 if (rc)
558 return rc; 559 return rc;
559 } 560 }
@@ -619,6 +620,118 @@ void gmap_discard(unsigned long from, unsigned long to, struct gmap *gmap)
619} 620}
620EXPORT_SYMBOL_GPL(gmap_discard); 621EXPORT_SYMBOL_GPL(gmap_discard);
621 622
623static LIST_HEAD(gmap_notifier_list);
624static DEFINE_SPINLOCK(gmap_notifier_lock);
625
626/**
627 * gmap_register_ipte_notifier - register a pte invalidation callback
628 * @nb: pointer to the gmap notifier block
629 */
630void gmap_register_ipte_notifier(struct gmap_notifier *nb)
631{
632 spin_lock(&gmap_notifier_lock);
633 list_add(&nb->list, &gmap_notifier_list);
634 spin_unlock(&gmap_notifier_lock);
635}
636EXPORT_SYMBOL_GPL(gmap_register_ipte_notifier);
637
638/**
639 * gmap_unregister_ipte_notifier - remove a pte invalidation callback
640 * @nb: pointer to the gmap notifier block
641 */
642void gmap_unregister_ipte_notifier(struct gmap_notifier *nb)
643{
644 spin_lock(&gmap_notifier_lock);
645 list_del_init(&nb->list);
646 spin_unlock(&gmap_notifier_lock);
647}
648EXPORT_SYMBOL_GPL(gmap_unregister_ipte_notifier);
649
650/**
651 * gmap_ipte_notify - mark a range of ptes for invalidation notification
652 * @gmap: pointer to guest mapping meta data structure
653 * @address: virtual address in the guest address space
654 * @len: size of area
655 *
656 * Returns 0 if for each page in the given range a gmap mapping exists and
657 * the invalidation notification could be set. If the gmap mapping is missing
658 * for one or more pages -EFAULT is returned. If no memory could be allocated
659 * -ENOMEM is returned. This function establishes missing page table entries.
660 */
661int gmap_ipte_notify(struct gmap *gmap, unsigned long start, unsigned long len)
662{
663 unsigned long addr;
664 spinlock_t *ptl;
665 pte_t *ptep, entry;
666 pgste_t pgste;
667 int rc = 0;
668
669 if ((start & ~PAGE_MASK) || (len & ~PAGE_MASK))
670 return -EINVAL;
671 down_read(&gmap->mm->mmap_sem);
672 while (len) {
673 /* Convert gmap address and connect the page tables */
674 addr = __gmap_fault(start, gmap);
675 if (IS_ERR_VALUE(addr)) {
676 rc = addr;
677 break;
678 }
679 /* Get the page mapped */
680 if (get_user_pages(current, gmap->mm, addr, 1, 1, 0,
681 NULL, NULL) != 1) {
682 rc = -EFAULT;
683 break;
684 }
685 /* Walk the process page table, lock and get pte pointer */
686 ptep = get_locked_pte(gmap->mm, addr, &ptl);
687 if (unlikely(!ptep))
688 continue;
689 /* Set notification bit in the pgste of the pte */
690 entry = *ptep;
691 if ((pte_val(entry) & (_PAGE_INVALID | _PAGE_RO)) == 0) {
692 pgste = pgste_get_lock(ptep);
693 pgste_val(pgste) |= RCP_IN_BIT;
694 pgste_set_unlock(ptep, pgste);
695 start += PAGE_SIZE;
696 len -= PAGE_SIZE;
697 }
698 spin_unlock(ptl);
699 }
700 up_read(&gmap->mm->mmap_sem);
701 return rc;
702}
703EXPORT_SYMBOL_GPL(gmap_ipte_notify);
704
705/**
706 * gmap_do_ipte_notify - call all invalidation callbacks for a specific pte.
707 * @mm: pointer to the process mm_struct
708 * @addr: virtual address in the process address space
709 * @pte: pointer to the page table entry
710 *
711 * This function is assumed to be called with the page table lock held
712 * for the pte to notify.
713 */
714void gmap_do_ipte_notify(struct mm_struct *mm, unsigned long addr, pte_t *pte)
715{
716 unsigned long segment_offset;
717 struct gmap_notifier *nb;
718 struct gmap_pgtable *mp;
719 struct gmap_rmap *rmap;
720 struct page *page;
721
722 segment_offset = ((unsigned long) pte) & (255 * sizeof(pte_t));
723 segment_offset = segment_offset * (4096 / sizeof(pte_t));
724 page = pfn_to_page(__pa(pte) >> PAGE_SHIFT);
725 mp = (struct gmap_pgtable *) page->index;
726 spin_lock(&gmap_notifier_lock);
727 list_for_each_entry(rmap, &mp->mapper, list) {
728 list_for_each_entry(nb, &gmap_notifier_list, list)
729 nb->notifier_call(rmap->gmap,
730 rmap->vmaddr + segment_offset);
731 }
732 spin_unlock(&gmap_notifier_lock);
733}
734
622static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm, 735static inline unsigned long *page_table_alloc_pgste(struct mm_struct *mm,
623 unsigned long vmaddr) 736 unsigned long vmaddr)
624{ 737{
diff --git a/arch/s390/mm/vmem.c b/arch/s390/mm/vmem.c
index 35837054f734..8b268fcc4612 100644
--- a/arch/s390/mm/vmem.c
+++ b/arch/s390/mm/vmem.c
@@ -375,9 +375,8 @@ void __init vmem_map_init(void)
375 375
376 ro_start = PFN_ALIGN((unsigned long)&_stext); 376 ro_start = PFN_ALIGN((unsigned long)&_stext);
377 ro_end = (unsigned long)&_eshared & PAGE_MASK; 377 ro_end = (unsigned long)&_eshared & PAGE_MASK;
378 for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { 378 for (i = 0; i < MEMORY_CHUNKS; i++) {
379 if (memory_chunk[i].type == CHUNK_CRASHK || 379 if (!memory_chunk[i].size)
380 memory_chunk[i].type == CHUNK_OLDMEM)
381 continue; 380 continue;
382 start = memory_chunk[i].addr; 381 start = memory_chunk[i].addr;
383 end = memory_chunk[i].addr + memory_chunk[i].size; 382 end = memory_chunk[i].addr + memory_chunk[i].size;
@@ -412,9 +411,6 @@ static int __init vmem_convert_memory_chunk(void)
412 for (i = 0; i < MEMORY_CHUNKS; i++) { 411 for (i = 0; i < MEMORY_CHUNKS; i++) {
413 if (!memory_chunk[i].size) 412 if (!memory_chunk[i].size)
414 continue; 413 continue;
415 if (memory_chunk[i].type == CHUNK_CRASHK ||
416 memory_chunk[i].type == CHUNK_OLDMEM)
417 continue;
418 seg = kzalloc(sizeof(*seg), GFP_KERNEL); 414 seg = kzalloc(sizeof(*seg), GFP_KERNEL);
419 if (!seg) 415 if (!seg)
420 panic("Out of memory...\n"); 416 panic("Out of memory...\n");