diff options
Diffstat (limited to 'arch/s390')
-rw-r--r-- | arch/s390/Kconfig | 5 | ||||
-rw-r--r-- | arch/s390/Makefile | 3 | ||||
-rw-r--r-- | arch/s390/kernel/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/kernel/cpcmd.c | 18 | ||||
-rw-r--r-- | arch/s390/kernel/head.S | 21 | ||||
-rw-r--r-- | arch/s390/kernel/head31.S | 8 | ||||
-rw-r--r-- | arch/s390/kernel/head64.S | 17 | ||||
-rw-r--r-- | arch/s390/kernel/ipl.c | 185 | ||||
-rw-r--r-- | arch/s390/kernel/machine_kexec.c | 78 | ||||
-rw-r--r-- | arch/s390/kernel/reipl.S | 17 | ||||
-rw-r--r-- | arch/s390/kernel/reipl64.S | 16 | ||||
-rw-r--r-- | arch/s390/kernel/relocate_kernel.S | 5 | ||||
-rw-r--r-- | arch/s390/kernel/relocate_kernel64.S | 5 | ||||
-rw-r--r-- | arch/s390/kernel/reset.S | 48 | ||||
-rw-r--r-- | arch/s390/kernel/setup.c | 66 | ||||
-rw-r--r-- | arch/s390/kernel/smp.c | 117 | ||||
-rw-r--r-- | arch/s390/kernel/traps.c | 30 | ||||
-rw-r--r-- | arch/s390/lib/Makefile | 2 | ||||
-rw-r--r-- | arch/s390/lib/uaccess_mvcos.c | 27 | ||||
-rw-r--r-- | arch/s390/lib/uaccess_pt.c | 153 | ||||
-rw-r--r-- | arch/s390/lib/uaccess_std.c | 67 | ||||
-rw-r--r-- | arch/s390/mm/extmem.c | 38 | ||||
-rw-r--r-- | arch/s390/mm/fault.c | 28 |
23 files changed, 574 insertions, 382 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 245b81bc7157..583d9ff0a571 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -33,9 +33,6 @@ config GENERIC_CALIBRATE_DELAY | |||
33 | config GENERIC_TIME | 33 | config GENERIC_TIME |
34 | def_bool y | 34 | def_bool y |
35 | 35 | ||
36 | config GENERIC_BUST_SPINLOCK | ||
37 | bool | ||
38 | |||
39 | mainmenu "Linux Kernel Configuration" | 36 | mainmenu "Linux Kernel Configuration" |
40 | 37 | ||
41 | config S390 | 38 | config S390 |
@@ -181,7 +178,7 @@ config PACK_STACK | |||
181 | 178 | ||
182 | config SMALL_STACK | 179 | config SMALL_STACK |
183 | bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb" | 180 | bool "Use 4kb/8kb for kernel stack instead of 8kb/16kb" |
184 | depends on PACK_STACK | 181 | depends on PACK_STACK && !LOCKDEP |
185 | help | 182 | help |
186 | If you say Y here and the compiler supports the -mkernel-backchain | 183 | If you say Y here and the compiler supports the -mkernel-backchain |
187 | option the kernel will use a smaller kernel stack size. For 31 bit | 184 | option the kernel will use a smaller kernel stack size. For 31 bit |
diff --git a/arch/s390/Makefile b/arch/s390/Makefile index 5deb9f7544a1..6598e5268573 100644 --- a/arch/s390/Makefile +++ b/arch/s390/Makefile | |||
@@ -35,6 +35,9 @@ cflags-$(CONFIG_MARCH_Z900) += $(call cc-option,-march=z900) | |||
35 | cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) | 35 | cflags-$(CONFIG_MARCH_Z990) += $(call cc-option,-march=z990) |
36 | cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109) | 36 | cflags-$(CONFIG_MARCH_Z9_109) += $(call cc-option,-march=z9-109) |
37 | 37 | ||
38 | #KBUILD_IMAGE is necessary for make rpm | ||
39 | KBUILD_IMAGE :=arch/s390/boot/image | ||
40 | |||
38 | # | 41 | # |
39 | # Prevent tail-call optimizations, to get clearer backtraces: | 42 | # Prevent tail-call optimizations, to get clearer backtraces: |
40 | # | 43 | # |
diff --git a/arch/s390/kernel/Makefile b/arch/s390/kernel/Makefile index aa978978d3d1..a81881c9b297 100644 --- a/arch/s390/kernel/Makefile +++ b/arch/s390/kernel/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | EXTRA_AFLAGS := -traditional | 5 | EXTRA_AFLAGS := -traditional |
6 | 6 | ||
7 | obj-y := bitmap.o traps.o time.o process.o \ | 7 | obj-y := bitmap.o traps.o time.o process.o reset.o \ |
8 | setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ | 8 | setup.o sys_s390.o ptrace.o signal.o cpcmd.o ebcdic.o \ |
9 | semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o | 9 | semaphore.o s390_ext.o debug.o profile.o irq.o ipl.o |
10 | 10 | ||
diff --git a/arch/s390/kernel/cpcmd.c b/arch/s390/kernel/cpcmd.c index 1eae74e72f95..a5972f1541fe 100644 --- a/arch/s390/kernel/cpcmd.c +++ b/arch/s390/kernel/cpcmd.c | |||
@@ -21,14 +21,15 @@ static DEFINE_SPINLOCK(cpcmd_lock); | |||
21 | static char cpcmd_buf[241]; | 21 | static char cpcmd_buf[241]; |
22 | 22 | ||
23 | /* | 23 | /* |
24 | * the caller of __cpcmd has to ensure that the response buffer is below 2 GB | 24 | * __cpcmd has some restrictions over cpcmd |
25 | * - the response buffer must reside below 2GB (if any) | ||
26 | * - __cpcmd is unlocked and therefore not SMP-safe | ||
25 | */ | 27 | */ |
26 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 28 | int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
27 | { | 29 | { |
28 | unsigned long flags, cmdlen; | 30 | unsigned cmdlen; |
29 | int return_code, return_len; | 31 | int return_code, return_len; |
30 | 32 | ||
31 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
32 | cmdlen = strlen(cmd); | 33 | cmdlen = strlen(cmd); |
33 | BUG_ON(cmdlen > 240); | 34 | BUG_ON(cmdlen > 240); |
34 | memcpy(cpcmd_buf, cmd, cmdlen); | 35 | memcpy(cpcmd_buf, cmd, cmdlen); |
@@ -74,7 +75,6 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
74 | : "+d" (reg3) : "d" (reg2) : "cc"); | 75 | : "+d" (reg3) : "d" (reg2) : "cc"); |
75 | return_code = (int) reg3; | 76 | return_code = (int) reg3; |
76 | } | 77 | } |
77 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
78 | if (response_code != NULL) | 78 | if (response_code != NULL) |
79 | *response_code = return_code; | 79 | *response_code = return_code; |
80 | return return_len; | 80 | return return_len; |
@@ -82,15 +82,18 @@ int __cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
82 | 82 | ||
83 | EXPORT_SYMBOL(__cpcmd); | 83 | EXPORT_SYMBOL(__cpcmd); |
84 | 84 | ||
85 | #ifdef CONFIG_64BIT | ||
86 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | 85 | int cpcmd(const char *cmd, char *response, int rlen, int *response_code) |
87 | { | 86 | { |
88 | char *lowbuf; | 87 | char *lowbuf; |
89 | int len; | 88 | int len; |
89 | unsigned long flags; | ||
90 | 90 | ||
91 | if ((rlen == 0) || (response == NULL) | 91 | if ((rlen == 0) || (response == NULL) |
92 | || !((unsigned long)response >> 31)) | 92 | || !((unsigned long)response >> 31)) { |
93 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
93 | len = __cpcmd(cmd, response, rlen, response_code); | 94 | len = __cpcmd(cmd, response, rlen, response_code); |
95 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
96 | } | ||
94 | else { | 97 | else { |
95 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); | 98 | lowbuf = kmalloc(rlen, GFP_KERNEL | GFP_DMA); |
96 | if (!lowbuf) { | 99 | if (!lowbuf) { |
@@ -98,7 +101,9 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
98 | "cpcmd: could not allocate response buffer\n"); | 101 | "cpcmd: could not allocate response buffer\n"); |
99 | return -ENOMEM; | 102 | return -ENOMEM; |
100 | } | 103 | } |
104 | spin_lock_irqsave(&cpcmd_lock, flags); | ||
101 | len = __cpcmd(cmd, lowbuf, rlen, response_code); | 105 | len = __cpcmd(cmd, lowbuf, rlen, response_code); |
106 | spin_unlock_irqrestore(&cpcmd_lock, flags); | ||
102 | memcpy(response, lowbuf, rlen); | 107 | memcpy(response, lowbuf, rlen); |
103 | kfree(lowbuf); | 108 | kfree(lowbuf); |
104 | } | 109 | } |
@@ -106,4 +111,3 @@ int cpcmd(const char *cmd, char *response, int rlen, int *response_code) | |||
106 | } | 111 | } |
107 | 112 | ||
108 | EXPORT_SYMBOL(cpcmd); | 113 | EXPORT_SYMBOL(cpcmd); |
109 | #endif /* CONFIG_64BIT */ | ||
diff --git a/arch/s390/kernel/head.S b/arch/s390/kernel/head.S index 0cf59bb7a857..8f8c802f1bcf 100644 --- a/arch/s390/kernel/head.S +++ b/arch/s390/kernel/head.S | |||
@@ -418,24 +418,6 @@ start: | |||
418 | .gotr: | 418 | .gotr: |
419 | l %r10,.tbl # EBCDIC to ASCII table | 419 | l %r10,.tbl # EBCDIC to ASCII table |
420 | tr 0(240,%r8),0(%r10) | 420 | tr 0(240,%r8),0(%r10) |
421 | stidp __LC_CPUID # Are we running on VM maybe | ||
422 | cli __LC_CPUID,0xff | ||
423 | bnz .test | ||
424 | .long 0x83300060 # diag 3,0,x'0060' - storage size | ||
425 | b .done | ||
426 | .test: | ||
427 | mvc 0x68(8),.pgmnw # set up pgm check handler | ||
428 | l %r2,.fourmeg | ||
429 | lr %r3,%r2 | ||
430 | bctr %r3,%r0 # 4M-1 | ||
431 | .loop: iske %r0,%r3 | ||
432 | ar %r3,%r2 | ||
433 | .pgmx: | ||
434 | sr %r3,%r2 | ||
435 | la %r3,1(%r3) | ||
436 | .done: | ||
437 | l %r1,.memsize | ||
438 | st %r3,ARCH_OFFSET(%r1) | ||
439 | slr %r0,%r0 | 421 | slr %r0,%r0 |
440 | st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11) | 422 | st %r0,INITRD_SIZE+ARCH_OFFSET-PARMAREA(%r11) |
441 | st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11) | 423 | st %r0,INITRD_START+ARCH_OFFSET-PARMAREA(%r11) |
@@ -443,9 +425,6 @@ start: | |||
443 | .tbl: .long _ebcasc # translate table | 425 | .tbl: .long _ebcasc # translate table |
444 | .cmd: .long COMMAND_LINE # address of command line buffer | 426 | .cmd: .long COMMAND_LINE # address of command line buffer |
445 | .parm: .long PARMAREA | 427 | .parm: .long PARMAREA |
446 | .memsize: .long memory_size | ||
447 | .fourmeg: .long 0x00400000 # 4M | ||
448 | .pgmnw: .long 0x00080000,.pgmx | ||
449 | .lowcase: | 428 | .lowcase: |
450 | .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 | 429 | .byte 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07 |
451 | .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f | 430 | .byte 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f |
diff --git a/arch/s390/kernel/head31.S b/arch/s390/kernel/head31.S index 0a2c929486ab..4388b3309e0c 100644 --- a/arch/s390/kernel/head31.S +++ b/arch/s390/kernel/head31.S | |||
@@ -131,10 +131,11 @@ startup_continue: | |||
131 | .long init_thread_union | 131 | .long init_thread_union |
132 | .Lpmask: | 132 | .Lpmask: |
133 | .byte 0 | 133 | .byte 0 |
134 | .align 8 | 134 | .align 8 |
135 | .Lpcext:.long 0x00080000,0x80000000 | 135 | .Lpcext:.long 0x00080000,0x80000000 |
136 | .Lcr: | 136 | .Lcr: |
137 | .long 0x00 # place holder for cr0 | 137 | .long 0x00 # place holder for cr0 |
138 | .align 8 | ||
138 | .Lwaitsclp: | 139 | .Lwaitsclp: |
139 | .long 0x010a0000,0x80000000 + .Lsclph | 140 | .long 0x010a0000,0x80000000 + .Lsclph |
140 | .Lrcp: | 141 | .Lrcp: |
@@ -156,7 +157,7 @@ startup_continue: | |||
156 | slr %r4,%r4 # set start of chunk to zero | 157 | slr %r4,%r4 # set start of chunk to zero |
157 | slr %r5,%r5 # set end of chunk to zero | 158 | slr %r5,%r5 # set end of chunk to zero |
158 | slr %r6,%r6 # set access code to zero | 159 | slr %r6,%r6 # set access code to zero |
159 | la %r10, MEMORY_CHUNKS # number of chunks | 160 | la %r10,MEMORY_CHUNKS # number of chunks |
160 | .Lloop: | 161 | .Lloop: |
161 | tprot 0(%r5),0 # test protection of first byte | 162 | tprot 0(%r5),0 # test protection of first byte |
162 | ipm %r7 | 163 | ipm %r7 |
@@ -176,8 +177,6 @@ startup_continue: | |||
176 | st %r0,4(%r3) # store size of chunk | 177 | st %r0,4(%r3) # store size of chunk |
177 | st %r6,8(%r3) # store type of chunk | 178 | st %r6,8(%r3) # store type of chunk |
178 | la %r3,12(%r3) | 179 | la %r3,12(%r3) |
179 | l %r4,.Lmemsize-.LPG1(%r13) # address of variable memory_size | ||
180 | st %r5,0(%r4) # store last end to memory size | ||
181 | ahi %r10,-1 # update chunk number | 180 | ahi %r10,-1 # update chunk number |
182 | .Lchkloop: | 181 | .Lchkloop: |
183 | lr %r6,%r7 # set access code to last cc | 182 | lr %r6,%r7 # set access code to last cc |
@@ -292,7 +291,6 @@ startup_continue: | |||
292 | .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg | 291 | .Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg |
293 | .Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte | 292 | .Lpcidte:.long 0x00080000,0x80000000 + .Lchkidte |
294 | .Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c | 293 | .Lpcdiag9c:.long 0x00080000,0x80000000 + .Lchkdiag9c |
295 | .Lmemsize:.long memory_size | ||
296 | .Lmchunk:.long memory_chunk | 294 | .Lmchunk:.long memory_chunk |
297 | .Lmflags:.long machine_flags | 295 | .Lmflags:.long machine_flags |
298 | .Lbss_bgn: .long __bss_start | 296 | .Lbss_bgn: .long __bss_start |
diff --git a/arch/s390/kernel/head64.S b/arch/s390/kernel/head64.S index 42f54d482441..c526279e1123 100644 --- a/arch/s390/kernel/head64.S +++ b/arch/s390/kernel/head64.S | |||
@@ -70,7 +70,20 @@ startup_continue: | |||
70 | sgr %r5,%r5 # set src,length and pad to zero | 70 | sgr %r5,%r5 # set src,length and pad to zero |
71 | mvcle %r2,%r4,0 # clear mem | 71 | mvcle %r2,%r4,0 # clear mem |
72 | jo .-4 # branch back, if not finish | 72 | jo .-4 # branch back, if not finish |
73 | # set program check new psw mask | ||
74 | mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) | ||
75 | larl %r1,.Lslowmemdetect # set program check address | ||
76 | stg %r1,__LC_PGM_NEW_PSW+8 | ||
77 | lghi %r1,0xc | ||
78 | diag %r0,%r1,0x260 # get memory size of virtual machine | ||
79 | cgr %r0,%r1 # different? -> old detection routine | ||
80 | jne .Lslowmemdetect | ||
81 | aghi %r1,1 # size is one more than end | ||
82 | larl %r2,memory_chunk | ||
83 | stg %r1,8(%r2) # store size of chunk | ||
84 | j .Ldonemem | ||
73 | 85 | ||
86 | .Lslowmemdetect: | ||
74 | l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word | 87 | l %r2,.Lrcp-.LPG1(%r13) # Read SCP forced command word |
75 | .Lservicecall: | 88 | .Lservicecall: |
76 | stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts | 89 | stosm .Lpmask-.LPG1(%r13),0x01 # authorize ext interrupts |
@@ -139,8 +152,6 @@ startup_continue: | |||
139 | .int 0x100000 | 152 | .int 0x100000 |
140 | 153 | ||
141 | .Lfchunk: | 154 | .Lfchunk: |
142 | # set program check new psw mask | ||
143 | mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13) | ||
144 | 155 | ||
145 | # | 156 | # |
146 | # find memory chunks. | 157 | # find memory chunks. |
@@ -175,8 +186,6 @@ startup_continue: | |||
175 | stg %r0,8(%r3) # store size of chunk | 186 | stg %r0,8(%r3) # store size of chunk |
176 | st %r6,20(%r3) # store type of chunk | 187 | st %r6,20(%r3) # store type of chunk |
177 | la %r3,24(%r3) | 188 | la %r3,24(%r3) |
178 | larl %r8,memory_size | ||
179 | stg %r5,0(%r8) # store memory size | ||
180 | ahi %r10,-1 # update chunk number | 189 | ahi %r10,-1 # update chunk number |
181 | .Lchkloop: | 190 | .Lchkloop: |
182 | lr %r6,%r7 # set access code to last cc | 191 | lr %r6,%r7 # set access code to last cc |
diff --git a/arch/s390/kernel/ipl.c b/arch/s390/kernel/ipl.c index 1f5e782b3d05..a36bea1188d9 100644 --- a/arch/s390/kernel/ipl.c +++ b/arch/s390/kernel/ipl.c | |||
@@ -13,12 +13,21 @@ | |||
13 | #include <linux/device.h> | 13 | #include <linux/device.h> |
14 | #include <linux/delay.h> | 14 | #include <linux/delay.h> |
15 | #include <linux/reboot.h> | 15 | #include <linux/reboot.h> |
16 | #include <linux/ctype.h> | ||
16 | #include <asm/smp.h> | 17 | #include <asm/smp.h> |
17 | #include <asm/setup.h> | 18 | #include <asm/setup.h> |
18 | #include <asm/cpcmd.h> | 19 | #include <asm/cpcmd.h> |
19 | #include <asm/cio.h> | 20 | #include <asm/cio.h> |
21 | #include <asm/ebcdic.h> | ||
22 | #include <asm/reset.h> | ||
20 | 23 | ||
21 | #define IPL_PARM_BLOCK_VERSION 0 | 24 | #define IPL_PARM_BLOCK_VERSION 0 |
25 | #define LOADPARM_LEN 8 | ||
26 | |||
27 | extern char s390_readinfo_sccb[]; | ||
28 | #define SCCB_VALID (*((__u16*)&s390_readinfo_sccb[6]) == 0x0010) | ||
29 | #define SCCB_LOADPARM (&s390_readinfo_sccb[24]) | ||
30 | #define SCCB_FLAG (s390_readinfo_sccb[91]) | ||
22 | 31 | ||
23 | enum ipl_type { | 32 | enum ipl_type { |
24 | IPL_TYPE_NONE = 1, | 33 | IPL_TYPE_NONE = 1, |
@@ -289,9 +298,25 @@ static struct attribute_group ipl_fcp_attr_group = { | |||
289 | 298 | ||
290 | /* CCW ipl device attributes */ | 299 | /* CCW ipl device attributes */ |
291 | 300 | ||
301 | static ssize_t ipl_ccw_loadparm_show(struct subsystem *subsys, char *page) | ||
302 | { | ||
303 | char loadparm[LOADPARM_LEN + 1] = {}; | ||
304 | |||
305 | if (!SCCB_VALID) | ||
306 | return sprintf(page, "#unknown#\n"); | ||
307 | memcpy(loadparm, SCCB_LOADPARM, LOADPARM_LEN); | ||
308 | EBCASC(loadparm, LOADPARM_LEN); | ||
309 | strstrip(loadparm); | ||
310 | return sprintf(page, "%s\n", loadparm); | ||
311 | } | ||
312 | |||
313 | static struct subsys_attribute sys_ipl_ccw_loadparm_attr = | ||
314 | __ATTR(loadparm, 0444, ipl_ccw_loadparm_show, NULL); | ||
315 | |||
292 | static struct attribute *ipl_ccw_attrs[] = { | 316 | static struct attribute *ipl_ccw_attrs[] = { |
293 | &sys_ipl_type_attr.attr, | 317 | &sys_ipl_type_attr.attr, |
294 | &sys_ipl_device_attr.attr, | 318 | &sys_ipl_device_attr.attr, |
319 | &sys_ipl_ccw_loadparm_attr.attr, | ||
295 | NULL, | 320 | NULL, |
296 | }; | 321 | }; |
297 | 322 | ||
@@ -348,8 +373,57 @@ static struct attribute_group reipl_fcp_attr_group = { | |||
348 | DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", | 373 | DEFINE_IPL_ATTR_RW(reipl_ccw, device, "0.0.%04llx\n", "0.0.%llx\n", |
349 | reipl_block_ccw->ipl_info.ccw.devno); | 374 | reipl_block_ccw->ipl_info.ccw.devno); |
350 | 375 | ||
376 | static void reipl_get_ascii_loadparm(char *loadparm) | ||
377 | { | ||
378 | memcpy(loadparm, &reipl_block_ccw->ipl_info.ccw.load_param, | ||
379 | LOADPARM_LEN); | ||
380 | EBCASC(loadparm, LOADPARM_LEN); | ||
381 | loadparm[LOADPARM_LEN] = 0; | ||
382 | strstrip(loadparm); | ||
383 | } | ||
384 | |||
385 | static ssize_t reipl_ccw_loadparm_show(struct subsystem *subsys, char *page) | ||
386 | { | ||
387 | char buf[LOADPARM_LEN + 1]; | ||
388 | |||
389 | reipl_get_ascii_loadparm(buf); | ||
390 | return sprintf(page, "%s\n", buf); | ||
391 | } | ||
392 | |||
393 | static ssize_t reipl_ccw_loadparm_store(struct subsystem *subsys, | ||
394 | const char *buf, size_t len) | ||
395 | { | ||
396 | int i, lp_len; | ||
397 | |||
398 | /* ignore trailing newline */ | ||
399 | lp_len = len; | ||
400 | if ((len > 0) && (buf[len - 1] == '\n')) | ||
401 | lp_len--; | ||
402 | /* loadparm can have max 8 characters and must not start with a blank */ | ||
403 | if ((lp_len > LOADPARM_LEN) || ((lp_len > 0) && (buf[0] == ' '))) | ||
404 | return -EINVAL; | ||
405 | /* loadparm can only contain "a-z,A-Z,0-9,SP,." */ | ||
406 | for (i = 0; i < lp_len; i++) { | ||
407 | if (isalpha(buf[i]) || isdigit(buf[i]) || (buf[i] == ' ') || | ||
408 | (buf[i] == '.')) | ||
409 | continue; | ||
410 | return -EINVAL; | ||
411 | } | ||
412 | /* initialize loadparm with blanks */ | ||
413 | memset(&reipl_block_ccw->ipl_info.ccw.load_param, ' ', LOADPARM_LEN); | ||
414 | /* copy and convert to ebcdic */ | ||
415 | memcpy(&reipl_block_ccw->ipl_info.ccw.load_param, buf, lp_len); | ||
416 | ASCEBC(reipl_block_ccw->ipl_info.ccw.load_param, LOADPARM_LEN); | ||
417 | return len; | ||
418 | } | ||
419 | |||
420 | static struct subsys_attribute sys_reipl_ccw_loadparm_attr = | ||
421 | __ATTR(loadparm, 0644, reipl_ccw_loadparm_show, | ||
422 | reipl_ccw_loadparm_store); | ||
423 | |||
351 | static struct attribute *reipl_ccw_attrs[] = { | 424 | static struct attribute *reipl_ccw_attrs[] = { |
352 | &sys_reipl_ccw_device_attr.attr, | 425 | &sys_reipl_ccw_device_attr.attr, |
426 | &sys_reipl_ccw_loadparm_attr.attr, | ||
353 | NULL, | 427 | NULL, |
354 | }; | 428 | }; |
355 | 429 | ||
@@ -502,23 +576,6 @@ static struct subsys_attribute dump_type_attr = | |||
502 | 576 | ||
503 | static decl_subsys(dump, NULL, NULL); | 577 | static decl_subsys(dump, NULL, NULL); |
504 | 578 | ||
505 | #ifdef CONFIG_SMP | ||
506 | static void dump_smp_stop_all(void) | ||
507 | { | ||
508 | int cpu; | ||
509 | preempt_disable(); | ||
510 | for_each_online_cpu(cpu) { | ||
511 | if (cpu == smp_processor_id()) | ||
512 | continue; | ||
513 | while (signal_processor(cpu, sigp_stop) == sigp_busy) | ||
514 | udelay(10); | ||
515 | } | ||
516 | preempt_enable(); | ||
517 | } | ||
518 | #else | ||
519 | #define dump_smp_stop_all() do { } while (0) | ||
520 | #endif | ||
521 | |||
522 | /* | 579 | /* |
523 | * Shutdown actions section | 580 | * Shutdown actions section |
524 | */ | 581 | */ |
@@ -571,11 +628,14 @@ void do_reipl(void) | |||
571 | { | 628 | { |
572 | struct ccw_dev_id devid; | 629 | struct ccw_dev_id devid; |
573 | static char buf[100]; | 630 | static char buf[100]; |
631 | char loadparm[LOADPARM_LEN + 1]; | ||
574 | 632 | ||
575 | switch (reipl_type) { | 633 | switch (reipl_type) { |
576 | case IPL_TYPE_CCW: | 634 | case IPL_TYPE_CCW: |
635 | reipl_get_ascii_loadparm(loadparm); | ||
577 | printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n", | 636 | printk(KERN_EMERG "reboot on ccw device: 0.0.%04x\n", |
578 | reipl_block_ccw->ipl_info.ccw.devno); | 637 | reipl_block_ccw->ipl_info.ccw.devno); |
638 | printk(KERN_EMERG "loadparm = '%s'\n", loadparm); | ||
579 | break; | 639 | break; |
580 | case IPL_TYPE_FCP: | 640 | case IPL_TYPE_FCP: |
581 | printk(KERN_EMERG "reboot on fcp device:\n"); | 641 | printk(KERN_EMERG "reboot on fcp device:\n"); |
@@ -588,12 +648,19 @@ void do_reipl(void) | |||
588 | switch (reipl_method) { | 648 | switch (reipl_method) { |
589 | case IPL_METHOD_CCW_CIO: | 649 | case IPL_METHOD_CCW_CIO: |
590 | devid.devno = reipl_block_ccw->ipl_info.ccw.devno; | 650 | devid.devno = reipl_block_ccw->ipl_info.ccw.devno; |
651 | if (ipl_get_type() == IPL_TYPE_CCW && devid.devno == ipl_devno) | ||
652 | diag308(DIAG308_IPL, NULL); | ||
591 | devid.ssid = 0; | 653 | devid.ssid = 0; |
592 | reipl_ccw_dev(&devid); | 654 | reipl_ccw_dev(&devid); |
593 | break; | 655 | break; |
594 | case IPL_METHOD_CCW_VM: | 656 | case IPL_METHOD_CCW_VM: |
595 | sprintf(buf, "IPL %X", reipl_block_ccw->ipl_info.ccw.devno); | 657 | if (strlen(loadparm) == 0) |
596 | cpcmd(buf, NULL, 0, NULL); | 658 | sprintf(buf, "IPL %X", |
659 | reipl_block_ccw->ipl_info.ccw.devno); | ||
660 | else | ||
661 | sprintf(buf, "IPL %X LOADPARM '%s'", | ||
662 | reipl_block_ccw->ipl_info.ccw.devno, loadparm); | ||
663 | __cpcmd(buf, NULL, 0, NULL); | ||
597 | break; | 664 | break; |
598 | case IPL_METHOD_CCW_DIAG: | 665 | case IPL_METHOD_CCW_DIAG: |
599 | diag308(DIAG308_SET, reipl_block_ccw); | 666 | diag308(DIAG308_SET, reipl_block_ccw); |
@@ -607,16 +674,17 @@ void do_reipl(void) | |||
607 | diag308(DIAG308_IPL, NULL); | 674 | diag308(DIAG308_IPL, NULL); |
608 | break; | 675 | break; |
609 | case IPL_METHOD_FCP_RO_VM: | 676 | case IPL_METHOD_FCP_RO_VM: |
610 | cpcmd("IPL", NULL, 0, NULL); | 677 | __cpcmd("IPL", NULL, 0, NULL); |
611 | break; | 678 | break; |
612 | case IPL_METHOD_NONE: | 679 | case IPL_METHOD_NONE: |
613 | default: | 680 | default: |
614 | if (MACHINE_IS_VM) | 681 | if (MACHINE_IS_VM) |
615 | cpcmd("IPL", NULL, 0, NULL); | 682 | __cpcmd("IPL", NULL, 0, NULL); |
616 | diag308(DIAG308_IPL, NULL); | 683 | diag308(DIAG308_IPL, NULL); |
617 | break; | 684 | break; |
618 | } | 685 | } |
619 | panic("reipl failed!\n"); | 686 | printk(KERN_EMERG "reboot failed!\n"); |
687 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | ||
620 | } | 688 | } |
621 | 689 | ||
622 | static void do_dump(void) | 690 | static void do_dump(void) |
@@ -639,17 +707,17 @@ static void do_dump(void) | |||
639 | 707 | ||
640 | switch (dump_method) { | 708 | switch (dump_method) { |
641 | case IPL_METHOD_CCW_CIO: | 709 | case IPL_METHOD_CCW_CIO: |
642 | dump_smp_stop_all(); | 710 | smp_send_stop(); |
643 | devid.devno = dump_block_ccw->ipl_info.ccw.devno; | 711 | devid.devno = dump_block_ccw->ipl_info.ccw.devno; |
644 | devid.ssid = 0; | 712 | devid.ssid = 0; |
645 | reipl_ccw_dev(&devid); | 713 | reipl_ccw_dev(&devid); |
646 | break; | 714 | break; |
647 | case IPL_METHOD_CCW_VM: | 715 | case IPL_METHOD_CCW_VM: |
648 | dump_smp_stop_all(); | 716 | smp_send_stop(); |
649 | sprintf(buf, "STORE STATUS"); | 717 | sprintf(buf, "STORE STATUS"); |
650 | cpcmd(buf, NULL, 0, NULL); | 718 | __cpcmd(buf, NULL, 0, NULL); |
651 | sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); | 719 | sprintf(buf, "IPL %X", dump_block_ccw->ipl_info.ccw.devno); |
652 | cpcmd(buf, NULL, 0, NULL); | 720 | __cpcmd(buf, NULL, 0, NULL); |
653 | break; | 721 | break; |
654 | case IPL_METHOD_CCW_DIAG: | 722 | case IPL_METHOD_CCW_DIAG: |
655 | diag308(DIAG308_SET, dump_block_ccw); | 723 | diag308(DIAG308_SET, dump_block_ccw); |
@@ -746,6 +814,17 @@ static int __init reipl_ccw_init(void) | |||
746 | reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; | 814 | reipl_block_ccw->hdr.version = IPL_PARM_BLOCK_VERSION; |
747 | reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); | 815 | reipl_block_ccw->hdr.blk0_len = sizeof(reipl_block_ccw->ipl_info.ccw); |
748 | reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; | 816 | reipl_block_ccw->hdr.pbt = DIAG308_IPL_TYPE_CCW; |
817 | /* check if read scp info worked and set loadparm */ | ||
818 | if (SCCB_VALID) | ||
819 | memcpy(reipl_block_ccw->ipl_info.ccw.load_param, | ||
820 | SCCB_LOADPARM, LOADPARM_LEN); | ||
821 | else | ||
822 | /* read scp info failed: set empty loadparm (EBCDIC blanks) */ | ||
823 | memset(reipl_block_ccw->ipl_info.ccw.load_param, 0x40, | ||
824 | LOADPARM_LEN); | ||
825 | /* FIXME: check for diag308_set_works when enabling diag ccw reipl */ | ||
826 | if (!MACHINE_IS_VM) | ||
827 | sys_reipl_ccw_loadparm_attr.attr.mode = S_IRUGO; | ||
749 | if (ipl_get_type() == IPL_TYPE_CCW) | 828 | if (ipl_get_type() == IPL_TYPE_CCW) |
750 | reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; | 829 | reipl_block_ccw->ipl_info.ccw.devno = ipl_devno; |
751 | reipl_capabilities |= IPL_TYPE_CCW; | 830 | reipl_capabilities |= IPL_TYPE_CCW; |
@@ -827,13 +906,11 @@ static int __init dump_ccw_init(void) | |||
827 | return 0; | 906 | return 0; |
828 | } | 907 | } |
829 | 908 | ||
830 | extern char s390_readinfo_sccb[]; | ||
831 | |||
832 | static int __init dump_fcp_init(void) | 909 | static int __init dump_fcp_init(void) |
833 | { | 910 | { |
834 | int rc; | 911 | int rc; |
835 | 912 | ||
836 | if(!(s390_readinfo_sccb[91] & 0x2)) | 913 | if(!(SCCB_FLAG & 0x2) || !SCCB_VALID) |
837 | return 0; /* LDIPL DUMP is not installed */ | 914 | return 0; /* LDIPL DUMP is not installed */ |
838 | if (!diag308_set_works) | 915 | if (!diag308_set_works) |
839 | return 0; | 916 | return 0; |
@@ -931,3 +1008,53 @@ static int __init s390_ipl_init(void) | |||
931 | } | 1008 | } |
932 | 1009 | ||
933 | __initcall(s390_ipl_init); | 1010 | __initcall(s390_ipl_init); |
1011 | |||
1012 | static LIST_HEAD(rcall); | ||
1013 | static DEFINE_MUTEX(rcall_mutex); | ||
1014 | |||
1015 | void register_reset_call(struct reset_call *reset) | ||
1016 | { | ||
1017 | mutex_lock(&rcall_mutex); | ||
1018 | list_add(&reset->list, &rcall); | ||
1019 | mutex_unlock(&rcall_mutex); | ||
1020 | } | ||
1021 | EXPORT_SYMBOL_GPL(register_reset_call); | ||
1022 | |||
1023 | void unregister_reset_call(struct reset_call *reset) | ||
1024 | { | ||
1025 | mutex_lock(&rcall_mutex); | ||
1026 | list_del(&reset->list); | ||
1027 | mutex_unlock(&rcall_mutex); | ||
1028 | } | ||
1029 | EXPORT_SYMBOL_GPL(unregister_reset_call); | ||
1030 | |||
1031 | static void do_reset_calls(void) | ||
1032 | { | ||
1033 | struct reset_call *reset; | ||
1034 | |||
1035 | list_for_each_entry(reset, &rcall, list) | ||
1036 | reset->fn(); | ||
1037 | } | ||
1038 | |||
1039 | extern void reset_mcck_handler(void); | ||
1040 | |||
1041 | void s390_reset_system(void) | ||
1042 | { | ||
1043 | struct _lowcore *lc; | ||
1044 | |||
1045 | /* Stack for interrupt/machine check handler */ | ||
1046 | lc = (struct _lowcore *)(unsigned long) store_prefix(); | ||
1047 | lc->panic_stack = S390_lowcore.panic_stack; | ||
1048 | |||
1049 | /* Disable prefixing */ | ||
1050 | set_prefix(0); | ||
1051 | |||
1052 | /* Disable lowcore protection */ | ||
1053 | __ctl_clear_bit(0,28); | ||
1054 | |||
1055 | /* Set new machine check handler */ | ||
1056 | S390_lowcore.mcck_new_psw.mask = PSW_KERNEL_BITS & ~PSW_MASK_MCHECK; | ||
1057 | S390_lowcore.mcck_new_psw.addr = | ||
1058 | PSW_ADDR_AMODE | (unsigned long) &reset_mcck_handler; | ||
1059 | do_reset_calls(); | ||
1060 | } | ||
diff --git a/arch/s390/kernel/machine_kexec.c b/arch/s390/kernel/machine_kexec.c index 60b1ea9f946b..f6d9bcc0f75b 100644 --- a/arch/s390/kernel/machine_kexec.c +++ b/arch/s390/kernel/machine_kexec.c | |||
@@ -1,15 +1,10 @@ | |||
1 | /* | 1 | /* |
2 | * arch/s390/kernel/machine_kexec.c | 2 | * arch/s390/kernel/machine_kexec.c |
3 | * | 3 | * |
4 | * (C) Copyright IBM Corp. 2005 | 4 | * Copyright IBM Corp. 2005,2006 |
5 | * | 5 | * |
6 | * Author(s): Rolf Adelsberger <adelsberger@de.ibm.com> | 6 | * Author(s): Rolf Adelsberger, |
7 | * | 7 | * Heiko Carstens <heiko.carstens@de.ibm.com> |
8 | */ | ||
9 | |||
10 | /* | ||
11 | * s390_machine_kexec.c - handle the transition of Linux booting another kernel | ||
12 | * on the S390 architecture. | ||
13 | */ | 8 | */ |
14 | 9 | ||
15 | #include <linux/device.h> | 10 | #include <linux/device.h> |
@@ -22,86 +17,49 @@ | |||
22 | #include <asm/pgalloc.h> | 17 | #include <asm/pgalloc.h> |
23 | #include <asm/system.h> | 18 | #include <asm/system.h> |
24 | #include <asm/smp.h> | 19 | #include <asm/smp.h> |
20 | #include <asm/reset.h> | ||
25 | 21 | ||
26 | static void kexec_halt_all_cpus(void *); | 22 | typedef void (*relocate_kernel_t)(kimage_entry_t *, unsigned long); |
27 | |||
28 | typedef void (*relocate_kernel_t) (kimage_entry_t *, unsigned long); | ||
29 | 23 | ||
30 | extern const unsigned char relocate_kernel[]; | 24 | extern const unsigned char relocate_kernel[]; |
31 | extern const unsigned long long relocate_kernel_len; | 25 | extern const unsigned long long relocate_kernel_len; |
32 | 26 | ||
33 | int | 27 | int machine_kexec_prepare(struct kimage *image) |
34 | machine_kexec_prepare(struct kimage *image) | ||
35 | { | 28 | { |
36 | unsigned long reboot_code_buffer; | 29 | void *reboot_code_buffer; |
37 | 30 | ||
38 | /* We don't support anything but the default image type for now. */ | 31 | /* We don't support anything but the default image type for now. */ |
39 | if (image->type != KEXEC_TYPE_DEFAULT) | 32 | if (image->type != KEXEC_TYPE_DEFAULT) |
40 | return -EINVAL; | 33 | return -EINVAL; |
41 | 34 | ||
42 | /* Get the destination where the assembler code should be copied to.*/ | 35 | /* Get the destination where the assembler code should be copied to.*/ |
43 | reboot_code_buffer = page_to_pfn(image->control_code_page)<<PAGE_SHIFT; | 36 | reboot_code_buffer = (void *) page_to_phys(image->control_code_page); |
44 | 37 | ||
45 | /* Then copy it */ | 38 | /* Then copy it */ |
46 | memcpy((void *) reboot_code_buffer, relocate_kernel, | 39 | memcpy(reboot_code_buffer, relocate_kernel, relocate_kernel_len); |
47 | relocate_kernel_len); | ||
48 | return 0; | 40 | return 0; |
49 | } | 41 | } |
50 | 42 | ||
51 | void | 43 | void machine_kexec_cleanup(struct kimage *image) |
52 | machine_kexec_cleanup(struct kimage *image) | ||
53 | { | 44 | { |
54 | } | 45 | } |
55 | 46 | ||
56 | void | 47 | void machine_shutdown(void) |
57 | machine_shutdown(void) | ||
58 | { | 48 | { |
59 | printk(KERN_INFO "kexec: machine_shutdown called\n"); | 49 | printk(KERN_INFO "kexec: machine_shutdown called\n"); |
60 | } | 50 | } |
61 | 51 | ||
62 | NORET_TYPE void | 52 | void machine_kexec(struct kimage *image) |
63 | machine_kexec(struct kimage *image) | ||
64 | { | 53 | { |
65 | clear_all_subchannels(); | ||
66 | cio_reset_channel_paths(); | ||
67 | |||
68 | /* Disable lowcore protection */ | ||
69 | ctl_clear_bit(0,28); | ||
70 | |||
71 | on_each_cpu(kexec_halt_all_cpus, image, 0, 0); | ||
72 | for (;;); | ||
73 | } | ||
74 | |||
75 | extern void pfault_fini(void); | ||
76 | |||
77 | static void | ||
78 | kexec_halt_all_cpus(void *kernel_image) | ||
79 | { | ||
80 | static atomic_t cpuid = ATOMIC_INIT(-1); | ||
81 | int cpu; | ||
82 | struct kimage *image; | ||
83 | relocate_kernel_t data_mover; | 54 | relocate_kernel_t data_mover; |
84 | 55 | ||
85 | #ifdef CONFIG_PFAULT | 56 | smp_send_stop(); |
86 | if (MACHINE_IS_VM) | 57 | pfault_fini(); |
87 | pfault_fini(); | 58 | s390_reset_system(); |
88 | #endif | ||
89 | 59 | ||
90 | if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) | 60 | data_mover = (relocate_kernel_t) page_to_phys(image->control_code_page); |
91 | signal_processor(smp_processor_id(), sigp_stop); | ||
92 | |||
93 | /* Wait for all other cpus to enter stopped state */ | ||
94 | for_each_online_cpu(cpu) { | ||
95 | if (cpu == smp_processor_id()) | ||
96 | continue; | ||
97 | while (!smp_cpu_not_running(cpu)) | ||
98 | cpu_relax(); | ||
99 | } | ||
100 | |||
101 | image = (struct kimage *) kernel_image; | ||
102 | data_mover = (relocate_kernel_t) | ||
103 | (page_to_pfn(image->control_code_page) << PAGE_SHIFT); | ||
104 | 61 | ||
105 | /* Call the moving routine */ | 62 | /* Call the moving routine */ |
106 | (*data_mover) (&image->head, image->start); | 63 | (*data_mover)(&image->head, image->start); |
64 | for (;;); | ||
107 | } | 65 | } |
diff --git a/arch/s390/kernel/reipl.S b/arch/s390/kernel/reipl.S index 0340477f3b08..f9434d42ce9f 100644 --- a/arch/s390/kernel/reipl.S +++ b/arch/s390/kernel/reipl.S | |||
@@ -11,19 +11,10 @@ | |||
11 | .globl do_reipl_asm | 11 | .globl do_reipl_asm |
12 | do_reipl_asm: basr %r13,0 | 12 | do_reipl_asm: basr %r13,0 |
13 | .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) | 13 | .Lpg0: lpsw .Lnewpsw-.Lpg0(%r13) |
14 | 14 | .Lpg1: # do store status of all registers | |
15 | # switch off lowcore protection | ||
16 | |||
17 | .Lpg1: stctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) | ||
18 | stctl %c0,%c0,.Lctlsave2-.Lpg0(%r13) | ||
19 | ni .Lctlsave1-.Lpg0(%r13),0xef | ||
20 | lctl %c0,%c0,.Lctlsave1-.Lpg0(%r13) | ||
21 | |||
22 | # do store status of all registers | ||
23 | 15 | ||
24 | stm %r0,%r15,__LC_GPREGS_SAVE_AREA | 16 | stm %r0,%r15,__LC_GPREGS_SAVE_AREA |
25 | stctl %c0,%c15,__LC_CREGS_SAVE_AREA | 17 | stctl %c0,%c15,__LC_CREGS_SAVE_AREA |
26 | mvc __LC_CREGS_SAVE_AREA(4),.Lctlsave2-.Lpg0(%r13) | ||
27 | stam %a0,%a15,__LC_AREGS_SAVE_AREA | 18 | stam %a0,%a15,__LC_AREGS_SAVE_AREA |
28 | stpx __LC_PREFIX_SAVE_AREA | 19 | stpx __LC_PREFIX_SAVE_AREA |
29 | stckc .Lclkcmp-.Lpg0(%r13) | 20 | stckc .Lclkcmp-.Lpg0(%r13) |
@@ -56,8 +47,7 @@ do_reipl_asm: basr %r13,0 | |||
56 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 | 47 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 |
57 | jz .L003 | 48 | jz .L003 |
58 | bas %r14,.Ldisab-.Lpg0(%r13) | 49 | bas %r14,.Ldisab-.Lpg0(%r13) |
59 | .L003: spx .Lnull-.Lpg0(%r13) | 50 | .L003: st %r1,__LC_SUBCHANNEL_ID |
60 | st %r1,__LC_SUBCHANNEL_ID | ||
61 | lpsw 0 | 51 | lpsw 0 |
62 | sigp 0,0,0(6) | 52 | sigp 0,0,0(6) |
63 | .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) | 53 | .Ldisab: st %r14,.Ldispsw+4-.Lpg0(%r13) |
@@ -65,9 +55,6 @@ do_reipl_asm: basr %r13,0 | |||
65 | .align 8 | 55 | .align 8 |
66 | .Lclkcmp: .quad 0x0000000000000000 | 56 | .Lclkcmp: .quad 0x0000000000000000 |
67 | .Lall: .long 0xff000000 | 57 | .Lall: .long 0xff000000 |
68 | .Lnull: .long 0x00000000 | ||
69 | .Lctlsave1: .long 0x00000000 | ||
70 | .Lctlsave2: .long 0x00000000 | ||
71 | .align 8 | 58 | .align 8 |
72 | .Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 | 59 | .Lnewpsw: .long 0x00080000,0x80000000+.Lpg1 |
73 | .Lpcnew: .long 0x00080000,0x80000000+.Lecs | 60 | .Lpcnew: .long 0x00080000,0x80000000+.Lecs |
diff --git a/arch/s390/kernel/reipl64.S b/arch/s390/kernel/reipl64.S index de7435054f7c..f18ef260ca23 100644 --- a/arch/s390/kernel/reipl64.S +++ b/arch/s390/kernel/reipl64.S | |||
@@ -10,10 +10,10 @@ | |||
10 | #include <asm/lowcore.h> | 10 | #include <asm/lowcore.h> |
11 | .globl do_reipl_asm | 11 | .globl do_reipl_asm |
12 | do_reipl_asm: basr %r13,0 | 12 | do_reipl_asm: basr %r13,0 |
13 | .Lpg0: lpswe .Lnewpsw-.Lpg0(%r13) | ||
14 | .Lpg1: # do store status of all registers | ||
13 | 15 | ||
14 | # do store status of all registers | 16 | stg %r1,.Lregsave-.Lpg0(%r13) |
15 | |||
16 | .Lpg0: stg %r1,.Lregsave-.Lpg0(%r13) | ||
17 | lghi %r1,0x1000 | 17 | lghi %r1,0x1000 |
18 | stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) | 18 | stmg %r0,%r15,__LC_GPREGS_SAVE_AREA-0x1000(%r1) |
19 | lg %r0,.Lregsave-.Lpg0(%r13) | 19 | lg %r0,.Lregsave-.Lpg0(%r13) |
@@ -27,11 +27,7 @@ do_reipl_asm: basr %r13,0 | |||
27 | stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) | 27 | stpt __LC_CPU_TIMER_SAVE_AREA-0x1000(%r1) |
28 | stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) | 28 | stg %r13, __LC_PSW_SAVE_AREA-0x1000+8(%r1) |
29 | 29 | ||
30 | lpswe .Lnewpsw-.Lpg0(%r13) | 30 | lctlg %c6,%c6,.Lall-.Lpg0(%r13) |
31 | .Lpg1: lctlg %c6,%c6,.Lall-.Lpg0(%r13) | ||
32 | stctg %c0,%c0,.Lregsave-.Lpg0(%r13) | ||
33 | ni .Lregsave+4-.Lpg0(%r13),0xef | ||
34 | lctlg %c0,%c0,.Lregsave-.Lpg0(%r13) | ||
35 | lgr %r1,%r2 | 31 | lgr %r1,%r2 |
36 | mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) | 32 | mvc __LC_PGM_NEW_PSW(16),.Lpcnew-.Lpg0(%r13) |
37 | stsch .Lschib-.Lpg0(%r13) | 33 | stsch .Lschib-.Lpg0(%r13) |
@@ -56,8 +52,7 @@ do_reipl_asm: basr %r13,0 | |||
56 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 | 52 | .L002: tm .Liplirb+8-.Lpg0(%r13),0xf3 |
57 | jz .L003 | 53 | jz .L003 |
58 | bas %r14,.Ldisab-.Lpg0(%r13) | 54 | bas %r14,.Ldisab-.Lpg0(%r13) |
59 | .L003: spx .Lnull-.Lpg0(%r13) | 55 | .L003: st %r1,__LC_SUBCHANNEL_ID |
60 | st %r1,__LC_SUBCHANNEL_ID | ||
61 | lhi %r1,0 # mode 0 = esa | 56 | lhi %r1,0 # mode 0 = esa |
62 | slr %r0,%r0 # set cpuid to zero | 57 | slr %r0,%r0 # set cpuid to zero |
63 | sigp %r1,%r0,0x12 # switch to esa mode | 58 | sigp %r1,%r0,0x12 # switch to esa mode |
@@ -70,7 +65,6 @@ do_reipl_asm: basr %r13,0 | |||
70 | .Lclkcmp: .quad 0x0000000000000000 | 65 | .Lclkcmp: .quad 0x0000000000000000 |
71 | .Lall: .quad 0x00000000ff000000 | 66 | .Lall: .quad 0x00000000ff000000 |
72 | .Lregsave: .quad 0x0000000000000000 | 67 | .Lregsave: .quad 0x0000000000000000 |
73 | .Lnull: .long 0x0000000000000000 | ||
74 | .align 16 | 68 | .align 16 |
75 | /* | 69 | /* |
76 | * These addresses have to be 31 bit otherwise | 70 | * These addresses have to be 31 bit otherwise |
diff --git a/arch/s390/kernel/relocate_kernel.S b/arch/s390/kernel/relocate_kernel.S index f9899ff2e5b0..3b456b80bcee 100644 --- a/arch/s390/kernel/relocate_kernel.S +++ b/arch/s390/kernel/relocate_kernel.S | |||
@@ -26,8 +26,7 @@ | |||
26 | relocate_kernel: | 26 | relocate_kernel: |
27 | basr %r13,0 # base address | 27 | basr %r13,0 # base address |
28 | .base: | 28 | .base: |
29 | stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQ (external) | 29 | stnsm sys_msk-.base(%r13),0xfb # disable DAT |
30 | spx zero64-.base(%r13) # absolute addressing mode | ||
31 | stctl %c0,%c15,ctlregs-.base(%r13) | 30 | stctl %c0,%c15,ctlregs-.base(%r13) |
32 | stm %r0,%r15,gprregs-.base(%r13) | 31 | stm %r0,%r15,gprregs-.base(%r13) |
33 | la %r1,load_psw-.base(%r13) | 32 | la %r1,load_psw-.base(%r13) |
@@ -97,8 +96,6 @@ | |||
97 | lpsw 0 # hopefully start new kernel... | 96 | lpsw 0 # hopefully start new kernel... |
98 | 97 | ||
99 | .align 8 | 98 | .align 8 |
100 | zero64: | ||
101 | .quad 0 | ||
102 | load_psw: | 99 | load_psw: |
103 | .long 0x00080000,0x80000000 | 100 | .long 0x00080000,0x80000000 |
104 | sys_msk: | 101 | sys_msk: |
diff --git a/arch/s390/kernel/relocate_kernel64.S b/arch/s390/kernel/relocate_kernel64.S index 4fb443042d9c..1f9ea2067b59 100644 --- a/arch/s390/kernel/relocate_kernel64.S +++ b/arch/s390/kernel/relocate_kernel64.S | |||
@@ -27,8 +27,7 @@ | |||
27 | relocate_kernel: | 27 | relocate_kernel: |
28 | basr %r13,0 # base address | 28 | basr %r13,0 # base address |
29 | .base: | 29 | .base: |
30 | stnsm sys_msk-.base(%r13),0xf8 # disable DAT and IRQs | 30 | stnsm sys_msk-.base(%r13),0xfb # disable DAT |
31 | spx zero64-.base(%r13) # absolute addressing mode | ||
32 | stctg %c0,%c15,ctlregs-.base(%r13) | 31 | stctg %c0,%c15,ctlregs-.base(%r13) |
33 | stmg %r0,%r15,gprregs-.base(%r13) | 32 | stmg %r0,%r15,gprregs-.base(%r13) |
34 | lghi %r0,3 | 33 | lghi %r0,3 |
@@ -100,8 +99,6 @@ | |||
100 | lpsw 0 # hopefully start new kernel... | 99 | lpsw 0 # hopefully start new kernel... |
101 | 100 | ||
102 | .align 8 | 101 | .align 8 |
103 | zero64: | ||
104 | .quad 0 | ||
105 | load_psw: | 102 | load_psw: |
106 | .long 0x00080000,0x80000000 | 103 | .long 0x00080000,0x80000000 |
107 | sys_msk: | 104 | sys_msk: |
diff --git a/arch/s390/kernel/reset.S b/arch/s390/kernel/reset.S new file mode 100644 index 000000000000..be8688c0665c --- /dev/null +++ b/arch/s390/kernel/reset.S | |||
@@ -0,0 +1,48 @@ | |||
1 | /* | ||
2 | * arch/s390/kernel/reset.S | ||
3 | * | ||
4 | * Copyright (C) IBM Corp. 2006 | ||
5 | * Author(s): Heiko Carstens <heiko.carstens@de.ibm.com> | ||
6 | */ | ||
7 | |||
8 | #include <asm/ptrace.h> | ||
9 | #include <asm/lowcore.h> | ||
10 | |||
11 | #ifdef CONFIG_64BIT | ||
12 | |||
13 | .globl reset_mcck_handler | ||
14 | reset_mcck_handler: | ||
15 | basr %r13,0 | ||
16 | 0: lg %r15,__LC_PANIC_STACK # load panic stack | ||
17 | aghi %r15,-STACK_FRAME_OVERHEAD | ||
18 | lg %r1,s390_reset_mcck_handler-0b(%r13) | ||
19 | ltgr %r1,%r1 | ||
20 | jz 1f | ||
21 | basr %r14,%r1 | ||
22 | 1: la %r1,4095 | ||
23 | lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1) | ||
24 | lpswe __LC_MCK_OLD_PSW | ||
25 | |||
26 | .globl s390_reset_mcck_handler | ||
27 | s390_reset_mcck_handler: | ||
28 | .quad 0 | ||
29 | |||
30 | #else /* CONFIG_64BIT */ | ||
31 | |||
32 | .globl reset_mcck_handler | ||
33 | reset_mcck_handler: | ||
34 | basr %r13,0 | ||
35 | 0: l %r15,__LC_PANIC_STACK # load panic stack | ||
36 | ahi %r15,-STACK_FRAME_OVERHEAD | ||
37 | l %r1,s390_reset_mcck_handler-0b(%r13) | ||
38 | ltr %r1,%r1 | ||
39 | jz 1f | ||
40 | basr %r14,%r1 | ||
41 | 1: lm %r0,%r15,__LC_GPREGS_SAVE_AREA | ||
42 | lpsw __LC_MCK_OLD_PSW | ||
43 | |||
44 | .globl s390_reset_mcck_handler | ||
45 | s390_reset_mcck_handler: | ||
46 | .long 0 | ||
47 | |||
48 | #endif /* CONFIG_64BIT */ | ||
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c index 2aa13e8e000a..b928fecdc743 100644 --- a/arch/s390/kernel/setup.c +++ b/arch/s390/kernel/setup.c | |||
@@ -62,13 +62,9 @@ EXPORT_SYMBOL_GPL(uaccess); | |||
62 | unsigned int console_mode = 0; | 62 | unsigned int console_mode = 0; |
63 | unsigned int console_devno = -1; | 63 | unsigned int console_devno = -1; |
64 | unsigned int console_irq = -1; | 64 | unsigned int console_irq = -1; |
65 | unsigned long memory_size = 0; | ||
66 | unsigned long machine_flags = 0; | 65 | unsigned long machine_flags = 0; |
67 | struct { | 66 | |
68 | unsigned long addr, size, type; | 67 | struct mem_chunk memory_chunk[MEMORY_CHUNKS]; |
69 | } memory_chunk[MEMORY_CHUNKS] = { { 0 } }; | ||
70 | #define CHUNK_READ_WRITE 0 | ||
71 | #define CHUNK_READ_ONLY 1 | ||
72 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ | 68 | volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */ |
73 | unsigned long __initdata zholes_size[MAX_NR_ZONES]; | 69 | unsigned long __initdata zholes_size[MAX_NR_ZONES]; |
74 | static unsigned long __initdata memory_end; | 70 | static unsigned long __initdata memory_end; |
@@ -229,11 +225,11 @@ static void __init conmode_default(void) | |||
229 | char *ptr; | 225 | char *ptr; |
230 | 226 | ||
231 | if (MACHINE_IS_VM) { | 227 | if (MACHINE_IS_VM) { |
232 | __cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); | 228 | cpcmd("QUERY CONSOLE", query_buffer, 1024, NULL); |
233 | console_devno = simple_strtoul(query_buffer + 5, NULL, 16); | 229 | console_devno = simple_strtoul(query_buffer + 5, NULL, 16); |
234 | ptr = strstr(query_buffer, "SUBCHANNEL ="); | 230 | ptr = strstr(query_buffer, "SUBCHANNEL ="); |
235 | console_irq = simple_strtoul(ptr + 13, NULL, 16); | 231 | console_irq = simple_strtoul(ptr + 13, NULL, 16); |
236 | __cpcmd("QUERY TERM", query_buffer, 1024, NULL); | 232 | cpcmd("QUERY TERM", query_buffer, 1024, NULL); |
237 | ptr = strstr(query_buffer, "CONMODE"); | 233 | ptr = strstr(query_buffer, "CONMODE"); |
238 | /* | 234 | /* |
239 | * Set the conmode to 3215 so that the device recognition | 235 | * Set the conmode to 3215 so that the device recognition |
@@ -242,7 +238,7 @@ static void __init conmode_default(void) | |||
242 | * 3215 and the 3270 driver will try to access the console | 238 | * 3215 and the 3270 driver will try to access the console |
243 | * device (3215 as console and 3270 as normal tty). | 239 | * device (3215 as console and 3270 as normal tty). |
244 | */ | 240 | */ |
245 | __cpcmd("TERM CONMODE 3215", NULL, 0, NULL); | 241 | cpcmd("TERM CONMODE 3215", NULL, 0, NULL); |
246 | if (ptr == NULL) { | 242 | if (ptr == NULL) { |
247 | #if defined(CONFIG_SCLP_CONSOLE) | 243 | #if defined(CONFIG_SCLP_CONSOLE) |
248 | SET_CONSOLE_SCLP; | 244 | SET_CONSOLE_SCLP; |
@@ -299,14 +295,14 @@ static void do_machine_restart_nonsmp(char * __unused) | |||
299 | static void do_machine_halt_nonsmp(void) | 295 | static void do_machine_halt_nonsmp(void) |
300 | { | 296 | { |
301 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) | 297 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) |
302 | cpcmd(vmhalt_cmd, NULL, 0, NULL); | 298 | __cpcmd(vmhalt_cmd, NULL, 0, NULL); |
303 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | 299 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); |
304 | } | 300 | } |
305 | 301 | ||
306 | static void do_machine_power_off_nonsmp(void) | 302 | static void do_machine_power_off_nonsmp(void) |
307 | { | 303 | { |
308 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) | 304 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) |
309 | cpcmd(vmpoff_cmd, NULL, 0, NULL); | 305 | __cpcmd(vmpoff_cmd, NULL, 0, NULL); |
310 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | 306 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); |
311 | } | 307 | } |
312 | 308 | ||
@@ -489,6 +485,37 @@ setup_resources(void) | |||
489 | } | 485 | } |
490 | } | 486 | } |
491 | 487 | ||
488 | static void __init setup_memory_end(void) | ||
489 | { | ||
490 | unsigned long real_size, memory_size; | ||
491 | unsigned long max_mem, max_phys; | ||
492 | int i; | ||
493 | |||
494 | memory_size = real_size = 0; | ||
495 | max_phys = VMALLOC_END - VMALLOC_MIN_SIZE; | ||
496 | memory_end &= PAGE_MASK; | ||
497 | |||
498 | max_mem = memory_end ? min(max_phys, memory_end) : max_phys; | ||
499 | |||
500 | for (i = 0; i < MEMORY_CHUNKS; i++) { | ||
501 | struct mem_chunk *chunk = &memory_chunk[i]; | ||
502 | |||
503 | real_size = max(real_size, chunk->addr + chunk->size); | ||
504 | if (chunk->addr >= max_mem) { | ||
505 | memset(chunk, 0, sizeof(*chunk)); | ||
506 | continue; | ||
507 | } | ||
508 | if (chunk->addr + chunk->size > max_mem) | ||
509 | chunk->size = max_mem - chunk->addr; | ||
510 | memory_size = max(memory_size, chunk->addr + chunk->size); | ||
511 | } | ||
512 | if (!memory_end) | ||
513 | memory_end = memory_size; | ||
514 | if (real_size > memory_end) | ||
515 | printk("More memory detected than supported. Unused: %luk\n", | ||
516 | (real_size - memory_end) >> 10); | ||
517 | } | ||
518 | |||
492 | static void __init | 519 | static void __init |
493 | setup_memory(void) | 520 | setup_memory(void) |
494 | { | 521 | { |
@@ -645,8 +672,6 @@ setup_arch(char **cmdline_p) | |||
645 | init_mm.end_data = (unsigned long) &_edata; | 672 | init_mm.end_data = (unsigned long) &_edata; |
646 | init_mm.brk = (unsigned long) &_end; | 673 | init_mm.brk = (unsigned long) &_end; |
647 | 674 | ||
648 | memory_end = memory_size; | ||
649 | |||
650 | if (MACHINE_HAS_MVCOS) | 675 | if (MACHINE_HAS_MVCOS) |
651 | memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess)); | 676 | memcpy(&uaccess, &uaccess_mvcos, sizeof(uaccess)); |
652 | else | 677 | else |
@@ -654,20 +679,7 @@ setup_arch(char **cmdline_p) | |||
654 | 679 | ||
655 | parse_early_param(); | 680 | parse_early_param(); |
656 | 681 | ||
657 | #ifndef CONFIG_64BIT | 682 | setup_memory_end(); |
658 | memory_end &= ~0x400000UL; | ||
659 | |||
660 | /* | ||
661 | * We need some free virtual space to be able to do vmalloc. | ||
662 | * On a machine with 2GB memory we make sure that we have at | ||
663 | * least 128 MB free space for vmalloc. | ||
664 | */ | ||
665 | if (memory_end > 1920*1024*1024) | ||
666 | memory_end = 1920*1024*1024; | ||
667 | #else /* CONFIG_64BIT */ | ||
668 | memory_end &= ~0x200000UL; | ||
669 | #endif /* CONFIG_64BIT */ | ||
670 | |||
671 | setup_memory(); | 683 | setup_memory(); |
672 | setup_resources(); | 684 | setup_resources(); |
673 | setup_lowcore(); | 685 | setup_lowcore(); |
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c index 62822245f9be..19090f7d4f51 100644 --- a/arch/s390/kernel/smp.c +++ b/arch/s390/kernel/smp.c | |||
@@ -230,18 +230,37 @@ static inline void do_store_status(void) | |||
230 | } | 230 | } |
231 | } | 231 | } |
232 | 232 | ||
233 | static inline void do_wait_for_stop(void) | ||
234 | { | ||
235 | int cpu; | ||
236 | |||
237 | /* Wait for all other cpus to enter stopped state */ | ||
238 | for_each_online_cpu(cpu) { | ||
239 | if (cpu == smp_processor_id()) | ||
240 | continue; | ||
241 | while(!smp_cpu_not_running(cpu)) | ||
242 | cpu_relax(); | ||
243 | } | ||
244 | } | ||
245 | |||
233 | /* | 246 | /* |
234 | * this function sends a 'stop' sigp to all other CPUs in the system. | 247 | * this function sends a 'stop' sigp to all other CPUs in the system. |
235 | * it goes straight through. | 248 | * it goes straight through. |
236 | */ | 249 | */ |
237 | void smp_send_stop(void) | 250 | void smp_send_stop(void) |
238 | { | 251 | { |
252 | /* Disable all interrupts/machine checks */ | ||
253 | __load_psw_mask(PSW_KERNEL_BITS & ~PSW_MASK_MCHECK); | ||
254 | |||
239 | /* write magic number to zero page (absolute 0) */ | 255 | /* write magic number to zero page (absolute 0) */ |
240 | lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; | 256 | lowcore_ptr[smp_processor_id()]->panic_magic = __PANIC_MAGIC; |
241 | 257 | ||
242 | /* stop other processors. */ | 258 | /* stop other processors. */ |
243 | do_send_stop(); | 259 | do_send_stop(); |
244 | 260 | ||
261 | /* wait until other processors are stopped */ | ||
262 | do_wait_for_stop(); | ||
263 | |||
245 | /* store status of other processors. */ | 264 | /* store status of other processors. */ |
246 | do_store_status(); | 265 | do_store_status(); |
247 | } | 266 | } |
@@ -250,88 +269,28 @@ void smp_send_stop(void) | |||
250 | * Reboot, halt and power_off routines for SMP. | 269 | * Reboot, halt and power_off routines for SMP. |
251 | */ | 270 | */ |
252 | 271 | ||
253 | static void do_machine_restart(void * __unused) | ||
254 | { | ||
255 | int cpu; | ||
256 | static atomic_t cpuid = ATOMIC_INIT(-1); | ||
257 | |||
258 | if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) != -1) | ||
259 | signal_processor(smp_processor_id(), sigp_stop); | ||
260 | |||
261 | /* Wait for all other cpus to enter stopped state */ | ||
262 | for_each_online_cpu(cpu) { | ||
263 | if (cpu == smp_processor_id()) | ||
264 | continue; | ||
265 | while(!smp_cpu_not_running(cpu)) | ||
266 | cpu_relax(); | ||
267 | } | ||
268 | |||
269 | /* Store status of other cpus. */ | ||
270 | do_store_status(); | ||
271 | |||
272 | /* | ||
273 | * Finally call reipl. Because we waited for all other | ||
274 | * cpus to enter this function we know that they do | ||
275 | * not hold any s390irq-locks (the cpus have been | ||
276 | * interrupted by an external interrupt and s390irq | ||
277 | * locks are always held disabled). | ||
278 | */ | ||
279 | do_reipl(); | ||
280 | } | ||
281 | |||
282 | void machine_restart_smp(char * __unused) | 272 | void machine_restart_smp(char * __unused) |
283 | { | 273 | { |
284 | on_each_cpu(do_machine_restart, NULL, 0, 0); | 274 | smp_send_stop(); |
285 | } | 275 | do_reipl(); |
286 | |||
287 | static void do_wait_for_stop(void) | ||
288 | { | ||
289 | unsigned long cr[16]; | ||
290 | |||
291 | __ctl_store(cr, 0, 15); | ||
292 | cr[0] &= ~0xffff; | ||
293 | cr[6] = 0; | ||
294 | __ctl_load(cr, 0, 15); | ||
295 | for (;;) | ||
296 | enabled_wait(); | ||
297 | } | ||
298 | |||
299 | static void do_machine_halt(void * __unused) | ||
300 | { | ||
301 | static atomic_t cpuid = ATOMIC_INIT(-1); | ||
302 | |||
303 | if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) == -1) { | ||
304 | smp_send_stop(); | ||
305 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) | ||
306 | cpcmd(vmhalt_cmd, NULL, 0, NULL); | ||
307 | signal_processor(smp_processor_id(), | ||
308 | sigp_stop_and_store_status); | ||
309 | } | ||
310 | do_wait_for_stop(); | ||
311 | } | 276 | } |
312 | 277 | ||
313 | void machine_halt_smp(void) | 278 | void machine_halt_smp(void) |
314 | { | 279 | { |
315 | on_each_cpu(do_machine_halt, NULL, 0, 0); | 280 | smp_send_stop(); |
316 | } | 281 | if (MACHINE_IS_VM && strlen(vmhalt_cmd) > 0) |
317 | 282 | __cpcmd(vmhalt_cmd, NULL, 0, NULL); | |
318 | static void do_machine_power_off(void * __unused) | 283 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); |
319 | { | 284 | for (;;); |
320 | static atomic_t cpuid = ATOMIC_INIT(-1); | ||
321 | |||
322 | if (atomic_cmpxchg(&cpuid, -1, smp_processor_id()) == -1) { | ||
323 | smp_send_stop(); | ||
324 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) | ||
325 | cpcmd(vmpoff_cmd, NULL, 0, NULL); | ||
326 | signal_processor(smp_processor_id(), | ||
327 | sigp_stop_and_store_status); | ||
328 | } | ||
329 | do_wait_for_stop(); | ||
330 | } | 285 | } |
331 | 286 | ||
332 | void machine_power_off_smp(void) | 287 | void machine_power_off_smp(void) |
333 | { | 288 | { |
334 | on_each_cpu(do_machine_power_off, NULL, 0, 0); | 289 | smp_send_stop(); |
290 | if (MACHINE_IS_VM && strlen(vmpoff_cmd) > 0) | ||
291 | __cpcmd(vmpoff_cmd, NULL, 0, NULL); | ||
292 | signal_processor(smp_processor_id(), sigp_stop_and_store_status); | ||
293 | for (;;); | ||
335 | } | 294 | } |
336 | 295 | ||
337 | /* | 296 | /* |
@@ -501,8 +460,6 @@ __init smp_count_cpus(void) | |||
501 | */ | 460 | */ |
502 | extern void init_cpu_timer(void); | 461 | extern void init_cpu_timer(void); |
503 | extern void init_cpu_vtimer(void); | 462 | extern void init_cpu_vtimer(void); |
504 | extern int pfault_init(void); | ||
505 | extern void pfault_fini(void); | ||
506 | 463 | ||
507 | int __devinit start_secondary(void *cpuvoid) | 464 | int __devinit start_secondary(void *cpuvoid) |
508 | { | 465 | { |
@@ -514,11 +471,9 @@ int __devinit start_secondary(void *cpuvoid) | |||
514 | #ifdef CONFIG_VIRT_TIMER | 471 | #ifdef CONFIG_VIRT_TIMER |
515 | init_cpu_vtimer(); | 472 | init_cpu_vtimer(); |
516 | #endif | 473 | #endif |
517 | #ifdef CONFIG_PFAULT | ||
518 | /* Enable pfault pseudo page faults on this cpu. */ | 474 | /* Enable pfault pseudo page faults on this cpu. */ |
519 | if (MACHINE_IS_VM) | 475 | pfault_init(); |
520 | pfault_init(); | 476 | |
521 | #endif | ||
522 | /* Mark this cpu as online */ | 477 | /* Mark this cpu as online */ |
523 | cpu_set(smp_processor_id(), cpu_online_map); | 478 | cpu_set(smp_processor_id(), cpu_online_map); |
524 | /* Switch on interrupts */ | 479 | /* Switch on interrupts */ |
@@ -708,11 +663,8 @@ __cpu_disable(void) | |||
708 | } | 663 | } |
709 | cpu_clear(cpu, cpu_online_map); | 664 | cpu_clear(cpu, cpu_online_map); |
710 | 665 | ||
711 | #ifdef CONFIG_PFAULT | ||
712 | /* Disable pfault pseudo page faults on this cpu. */ | 666 | /* Disable pfault pseudo page faults on this cpu. */ |
713 | if (MACHINE_IS_VM) | 667 | pfault_fini(); |
714 | pfault_fini(); | ||
715 | #endif | ||
716 | 668 | ||
717 | memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals)); | 669 | memset(&cr_parms.orvals, 0, sizeof(cr_parms.orvals)); |
718 | memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals)); | 670 | memset(&cr_parms.andvals, 0xff, sizeof(cr_parms.andvals)); |
@@ -860,4 +812,3 @@ EXPORT_SYMBOL(smp_ctl_clear_bit); | |||
860 | EXPORT_SYMBOL(smp_call_function); | 812 | EXPORT_SYMBOL(smp_call_function); |
861 | EXPORT_SYMBOL(smp_get_cpu); | 813 | EXPORT_SYMBOL(smp_get_cpu); |
862 | EXPORT_SYMBOL(smp_put_cpu); | 814 | EXPORT_SYMBOL(smp_put_cpu); |
863 | |||
diff --git a/arch/s390/kernel/traps.c b/arch/s390/kernel/traps.c index 92ecffbc8d82..3cbb0dcf1f1d 100644 --- a/arch/s390/kernel/traps.c +++ b/arch/s390/kernel/traps.c | |||
@@ -58,12 +58,6 @@ int sysctl_userprocess_debug = 0; | |||
58 | 58 | ||
59 | extern pgm_check_handler_t do_protection_exception; | 59 | extern pgm_check_handler_t do_protection_exception; |
60 | extern pgm_check_handler_t do_dat_exception; | 60 | extern pgm_check_handler_t do_dat_exception; |
61 | #ifdef CONFIG_PFAULT | ||
62 | extern int pfault_init(void); | ||
63 | extern void pfault_fini(void); | ||
64 | extern void pfault_interrupt(__u16 error_code); | ||
65 | static ext_int_info_t ext_int_pfault; | ||
66 | #endif | ||
67 | extern pgm_check_handler_t do_monitor_call; | 61 | extern pgm_check_handler_t do_monitor_call; |
68 | 62 | ||
69 | #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) | 63 | #define stack_pointer ({ void **sp; asm("la %0,0(15)" : "=&d" (sp)); sp; }) |
@@ -135,7 +129,7 @@ __show_trace(unsigned long sp, unsigned long low, unsigned long high) | |||
135 | } | 129 | } |
136 | } | 130 | } |
137 | 131 | ||
138 | void show_trace(struct task_struct *task, unsigned long * stack) | 132 | void show_trace(struct task_struct *task, unsigned long *stack) |
139 | { | 133 | { |
140 | register unsigned long __r15 asm ("15"); | 134 | register unsigned long __r15 asm ("15"); |
141 | unsigned long sp; | 135 | unsigned long sp; |
@@ -157,6 +151,9 @@ void show_trace(struct task_struct *task, unsigned long * stack) | |||
157 | __show_trace(sp, S390_lowcore.thread_info, | 151 | __show_trace(sp, S390_lowcore.thread_info, |
158 | S390_lowcore.thread_info + THREAD_SIZE); | 152 | S390_lowcore.thread_info + THREAD_SIZE); |
159 | printk("\n"); | 153 | printk("\n"); |
154 | if (!task) | ||
155 | task = current; | ||
156 | debug_show_held_locks(task); | ||
160 | } | 157 | } |
161 | 158 | ||
162 | void show_stack(struct task_struct *task, unsigned long *sp) | 159 | void show_stack(struct task_struct *task, unsigned long *sp) |
@@ -739,22 +736,5 @@ void __init trap_init(void) | |||
739 | pgm_check_table[0x1C] = &space_switch_exception; | 736 | pgm_check_table[0x1C] = &space_switch_exception; |
740 | pgm_check_table[0x1D] = &hfp_sqrt_exception; | 737 | pgm_check_table[0x1D] = &hfp_sqrt_exception; |
741 | pgm_check_table[0x40] = &do_monitor_call; | 738 | pgm_check_table[0x40] = &do_monitor_call; |
742 | 739 | pfault_irq_init(); | |
743 | if (MACHINE_IS_VM) { | ||
744 | #ifdef CONFIG_PFAULT | ||
745 | /* | ||
746 | * Try to get pfault pseudo page faults going. | ||
747 | */ | ||
748 | if (register_early_external_interrupt(0x2603, pfault_interrupt, | ||
749 | &ext_int_pfault) != 0) | ||
750 | panic("Couldn't request external interrupt 0x2603"); | ||
751 | |||
752 | if (pfault_init() == 0) | ||
753 | return; | ||
754 | |||
755 | /* Tough luck, no pfault. */ | ||
756 | unregister_early_external_interrupt(0x2603, pfault_interrupt, | ||
757 | &ext_int_pfault); | ||
758 | #endif | ||
759 | } | ||
760 | } | 740 | } |
diff --git a/arch/s390/lib/Makefile b/arch/s390/lib/Makefile index b0cfa6c4883d..b5f94cf3bde8 100644 --- a/arch/s390/lib/Makefile +++ b/arch/s390/lib/Makefile | |||
@@ -4,7 +4,7 @@ | |||
4 | 4 | ||
5 | EXTRA_AFLAGS := -traditional | 5 | EXTRA_AFLAGS := -traditional |
6 | 6 | ||
7 | lib-y += delay.o string.o uaccess_std.o | 7 | lib-y += delay.o string.o uaccess_std.o uaccess_pt.o |
8 | lib-$(CONFIG_32BIT) += div64.o | 8 | lib-$(CONFIG_32BIT) += div64.o |
9 | lib-$(CONFIG_64BIT) += uaccess_mvcos.o | 9 | lib-$(CONFIG_64BIT) += uaccess_mvcos.o |
10 | lib-$(CONFIG_SMP) += spinlock.o | 10 | lib-$(CONFIG_SMP) += spinlock.o |
diff --git a/arch/s390/lib/uaccess_mvcos.c b/arch/s390/lib/uaccess_mvcos.c index 121b2935a422..f9a23d57eb79 100644 --- a/arch/s390/lib/uaccess_mvcos.c +++ b/arch/s390/lib/uaccess_mvcos.c | |||
@@ -27,6 +27,9 @@ | |||
27 | #define SLR "slgr" | 27 | #define SLR "slgr" |
28 | #endif | 28 | #endif |
29 | 29 | ||
30 | extern size_t copy_from_user_std(size_t, const void __user *, void *); | ||
31 | extern size_t copy_to_user_std(size_t, void __user *, const void *); | ||
32 | |||
30 | size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) | 33 | size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) |
31 | { | 34 | { |
32 | register unsigned long reg0 asm("0") = 0x81UL; | 35 | register unsigned long reg0 asm("0") = 0x81UL; |
@@ -66,6 +69,13 @@ size_t copy_from_user_mvcos(size_t size, const void __user *ptr, void *x) | |||
66 | return size; | 69 | return size; |
67 | } | 70 | } |
68 | 71 | ||
72 | size_t copy_from_user_mvcos_check(size_t size, const void __user *ptr, void *x) | ||
73 | { | ||
74 | if (size <= 256) | ||
75 | return copy_from_user_std(size, ptr, x); | ||
76 | return copy_from_user_mvcos(size, ptr, x); | ||
77 | } | ||
78 | |||
69 | size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) | 79 | size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) |
70 | { | 80 | { |
71 | register unsigned long reg0 asm("0") = 0x810000UL; | 81 | register unsigned long reg0 asm("0") = 0x810000UL; |
@@ -95,6 +105,13 @@ size_t copy_to_user_mvcos(size_t size, void __user *ptr, const void *x) | |||
95 | return size; | 105 | return size; |
96 | } | 106 | } |
97 | 107 | ||
108 | size_t copy_to_user_mvcos_check(size_t size, void __user *ptr, const void *x) | ||
109 | { | ||
110 | if (size <= 256) | ||
111 | return copy_to_user_std(size, ptr, x); | ||
112 | return copy_to_user_mvcos(size, ptr, x); | ||
113 | } | ||
114 | |||
98 | size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from) | 115 | size_t copy_in_user_mvcos(size_t size, void __user *to, const void __user *from) |
99 | { | 116 | { |
100 | register unsigned long reg0 asm("0") = 0x810081UL; | 117 | register unsigned long reg0 asm("0") = 0x810081UL; |
@@ -145,18 +162,16 @@ size_t clear_user_mvcos(size_t size, void __user *to) | |||
145 | return size; | 162 | return size; |
146 | } | 163 | } |
147 | 164 | ||
148 | extern size_t copy_from_user_std_small(size_t, const void __user *, void *); | ||
149 | extern size_t copy_to_user_std_small(size_t, void __user *, const void *); | ||
150 | extern size_t strnlen_user_std(size_t, const char __user *); | 165 | extern size_t strnlen_user_std(size_t, const char __user *); |
151 | extern size_t strncpy_from_user_std(size_t, const char __user *, char *); | 166 | extern size_t strncpy_from_user_std(size_t, const char __user *, char *); |
152 | extern int futex_atomic_op(int, int __user *, int, int *); | 167 | extern int futex_atomic_op(int, int __user *, int, int *); |
153 | extern int futex_atomic_cmpxchg(int __user *, int, int); | 168 | extern int futex_atomic_cmpxchg(int __user *, int, int); |
154 | 169 | ||
155 | struct uaccess_ops uaccess_mvcos = { | 170 | struct uaccess_ops uaccess_mvcos = { |
156 | .copy_from_user = copy_from_user_mvcos, | 171 | .copy_from_user = copy_from_user_mvcos_check, |
157 | .copy_from_user_small = copy_from_user_std_small, | 172 | .copy_from_user_small = copy_from_user_std, |
158 | .copy_to_user = copy_to_user_mvcos, | 173 | .copy_to_user = copy_to_user_mvcos_check, |
159 | .copy_to_user_small = copy_to_user_std_small, | 174 | .copy_to_user_small = copy_to_user_std, |
160 | .copy_in_user = copy_in_user_mvcos, | 175 | .copy_in_user = copy_in_user_mvcos, |
161 | .clear_user = clear_user_mvcos, | 176 | .clear_user = clear_user_mvcos, |
162 | .strnlen_user = strnlen_user_std, | 177 | .strnlen_user = strnlen_user_std, |
diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c new file mode 100644 index 000000000000..8741bdc09299 --- /dev/null +++ b/arch/s390/lib/uaccess_pt.c | |||
@@ -0,0 +1,153 @@ | |||
1 | /* | ||
2 | * arch/s390/lib/uaccess_pt.c | ||
3 | * | ||
4 | * User access functions based on page table walks. | ||
5 | * | ||
6 | * Copyright IBM Corp. 2006 | ||
7 | * Author(s): Gerald Schaefer (gerald.schaefer@de.ibm.com) | ||
8 | */ | ||
9 | |||
10 | #include <linux/errno.h> | ||
11 | #include <asm/uaccess.h> | ||
12 | #include <linux/mm.h> | ||
13 | #include <asm/futex.h> | ||
14 | |||
15 | static inline int __handle_fault(struct mm_struct *mm, unsigned long address, | ||
16 | int write_access) | ||
17 | { | ||
18 | struct vm_area_struct *vma; | ||
19 | int ret = -EFAULT; | ||
20 | |||
21 | down_read(&mm->mmap_sem); | ||
22 | vma = find_vma(mm, address); | ||
23 | if (unlikely(!vma)) | ||
24 | goto out; | ||
25 | if (unlikely(vma->vm_start > address)) { | ||
26 | if (!(vma->vm_flags & VM_GROWSDOWN)) | ||
27 | goto out; | ||
28 | if (expand_stack(vma, address)) | ||
29 | goto out; | ||
30 | } | ||
31 | |||
32 | if (!write_access) { | ||
33 | /* page not present, check vm flags */ | ||
34 | if (!(vma->vm_flags & (VM_READ | VM_EXEC | VM_WRITE))) | ||
35 | goto out; | ||
36 | } else { | ||
37 | if (!(vma->vm_flags & VM_WRITE)) | ||
38 | goto out; | ||
39 | } | ||
40 | |||
41 | survive: | ||
42 | switch (handle_mm_fault(mm, vma, address, write_access)) { | ||
43 | case VM_FAULT_MINOR: | ||
44 | current->min_flt++; | ||
45 | break; | ||
46 | case VM_FAULT_MAJOR: | ||
47 | current->maj_flt++; | ||
48 | break; | ||
49 | case VM_FAULT_SIGBUS: | ||
50 | goto out_sigbus; | ||
51 | case VM_FAULT_OOM: | ||
52 | goto out_of_memory; | ||
53 | default: | ||
54 | BUG(); | ||
55 | } | ||
56 | ret = 0; | ||
57 | out: | ||
58 | up_read(&mm->mmap_sem); | ||
59 | return ret; | ||
60 | |||
61 | out_of_memory: | ||
62 | up_read(&mm->mmap_sem); | ||
63 | if (current->pid == 1) { | ||
64 | yield(); | ||
65 | goto survive; | ||
66 | } | ||
67 | printk("VM: killing process %s\n", current->comm); | ||
68 | return ret; | ||
69 | |||
70 | out_sigbus: | ||
71 | up_read(&mm->mmap_sem); | ||
72 | current->thread.prot_addr = address; | ||
73 | current->thread.trap_no = 0x11; | ||
74 | force_sig(SIGBUS, current); | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | static inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, | ||
79 | size_t n, int write_user) | ||
80 | { | ||
81 | struct mm_struct *mm = current->mm; | ||
82 | unsigned long offset, pfn, done, size; | ||
83 | pgd_t *pgd; | ||
84 | pmd_t *pmd; | ||
85 | pte_t *pte; | ||
86 | void *from, *to; | ||
87 | |||
88 | done = 0; | ||
89 | retry: | ||
90 | spin_lock(&mm->page_table_lock); | ||
91 | do { | ||
92 | pgd = pgd_offset(mm, uaddr); | ||
93 | if (pgd_none(*pgd) || unlikely(pgd_bad(*pgd))) | ||
94 | goto fault; | ||
95 | |||
96 | pmd = pmd_offset(pgd, uaddr); | ||
97 | if (pmd_none(*pmd) || unlikely(pmd_bad(*pmd))) | ||
98 | goto fault; | ||
99 | |||
100 | pte = pte_offset_map(pmd, uaddr); | ||
101 | if (!pte || !pte_present(*pte) || | ||
102 | (write_user && !pte_write(*pte))) | ||
103 | goto fault; | ||
104 | |||
105 | pfn = pte_pfn(*pte); | ||
106 | if (!pfn_valid(pfn)) | ||
107 | goto out; | ||
108 | |||
109 | offset = uaddr & (PAGE_SIZE - 1); | ||
110 | size = min(n - done, PAGE_SIZE - offset); | ||
111 | if (write_user) { | ||
112 | to = (void *)((pfn << PAGE_SHIFT) + offset); | ||
113 | from = kptr + done; | ||
114 | } else { | ||
115 | from = (void *)((pfn << PAGE_SHIFT) + offset); | ||
116 | to = kptr + done; | ||
117 | } | ||
118 | memcpy(to, from, size); | ||
119 | done += size; | ||
120 | uaddr += size; | ||
121 | } while (done < n); | ||
122 | out: | ||
123 | spin_unlock(&mm->page_table_lock); | ||
124 | return n - done; | ||
125 | fault: | ||
126 | spin_unlock(&mm->page_table_lock); | ||
127 | if (__handle_fault(mm, uaddr, write_user)) | ||
128 | return n - done; | ||
129 | goto retry; | ||
130 | } | ||
131 | |||
132 | size_t copy_from_user_pt(size_t n, const void __user *from, void *to) | ||
133 | { | ||
134 | size_t rc; | ||
135 | |||
136 | if (segment_eq(get_fs(), KERNEL_DS)) { | ||
137 | memcpy(to, (void __kernel __force *) from, n); | ||
138 | return 0; | ||
139 | } | ||
140 | rc = __user_copy_pt((unsigned long) from, to, n, 0); | ||
141 | if (unlikely(rc)) | ||
142 | memset(to + n - rc, 0, rc); | ||
143 | return rc; | ||
144 | } | ||
145 | |||
146 | size_t copy_to_user_pt(size_t n, void __user *to, const void *from) | ||
147 | { | ||
148 | if (segment_eq(get_fs(), KERNEL_DS)) { | ||
149 | memcpy((void __kernel __force *) to, from, n); | ||
150 | return 0; | ||
151 | } | ||
152 | return __user_copy_pt((unsigned long) to, (void *) from, n, 1); | ||
153 | } | ||
diff --git a/arch/s390/lib/uaccess_std.c b/arch/s390/lib/uaccess_std.c index f44f0078b354..2d549ed2e113 100644 --- a/arch/s390/lib/uaccess_std.c +++ b/arch/s390/lib/uaccess_std.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #define SLR "slgr" | 28 | #define SLR "slgr" |
29 | #endif | 29 | #endif |
30 | 30 | ||
31 | extern size_t copy_from_user_pt(size_t n, const void __user *from, void *to); | ||
32 | extern size_t copy_to_user_pt(size_t n, void __user *to, const void *from); | ||
33 | |||
31 | size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) | 34 | size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) |
32 | { | 35 | { |
33 | unsigned long tmp1, tmp2; | 36 | unsigned long tmp1, tmp2; |
@@ -69,34 +72,11 @@ size_t copy_from_user_std(size_t size, const void __user *ptr, void *x) | |||
69 | return size; | 72 | return size; |
70 | } | 73 | } |
71 | 74 | ||
72 | size_t copy_from_user_std_small(size_t size, const void __user *ptr, void *x) | 75 | size_t copy_from_user_std_check(size_t size, const void __user *ptr, void *x) |
73 | { | 76 | { |
74 | unsigned long tmp1, tmp2; | 77 | if (size <= 1024) |
75 | 78 | return copy_from_user_std(size, ptr, x); | |
76 | tmp1 = 0UL; | 79 | return copy_from_user_pt(size, ptr, x); |
77 | asm volatile( | ||
78 | "0: mvcp 0(%0,%2),0(%1),%3\n" | ||
79 | " "SLR" %0,%0\n" | ||
80 | " j 5f\n" | ||
81 | "1: la %4,255(%1)\n" /* %4 = ptr + 255 */ | ||
82 | " "LHI" %3,-4096\n" | ||
83 | " nr %4,%3\n" /* %4 = (ptr + 255) & -4096 */ | ||
84 | " "SLR" %4,%1\n" | ||
85 | " "CLR" %0,%4\n" /* copy crosses next page boundary? */ | ||
86 | " jnh 5f\n" | ||
87 | "2: mvcp 0(%4,%2),0(%1),%3\n" | ||
88 | " "SLR" %0,%4\n" | ||
89 | " "ALR" %2,%4\n" | ||
90 | "3:"LHI" %4,-1\n" | ||
91 | " "ALR" %4,%0\n" /* copy remaining size, subtract 1 */ | ||
92 | " bras %3,4f\n" | ||
93 | " xc 0(1,%2),0(%2)\n" | ||
94 | "4: ex %4,0(%3)\n" | ||
95 | "5:\n" | ||
96 | EX_TABLE(0b,1b) EX_TABLE(2b,3b) | ||
97 | : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) | ||
98 | : : "cc", "memory"); | ||
99 | return size; | ||
100 | } | 80 | } |
101 | 81 | ||
102 | size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) | 82 | size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) |
@@ -130,28 +110,11 @@ size_t copy_to_user_std(size_t size, void __user *ptr, const void *x) | |||
130 | return size; | 110 | return size; |
131 | } | 111 | } |
132 | 112 | ||
133 | size_t copy_to_user_std_small(size_t size, void __user *ptr, const void *x) | 113 | size_t copy_to_user_std_check(size_t size, void __user *ptr, const void *x) |
134 | { | 114 | { |
135 | unsigned long tmp1, tmp2; | 115 | if (size <= 1024) |
136 | 116 | return copy_to_user_std(size, ptr, x); | |
137 | tmp1 = 0UL; | 117 | return copy_to_user_pt(size, ptr, x); |
138 | asm volatile( | ||
139 | "0: mvcs 0(%0,%1),0(%2),%3\n" | ||
140 | " "SLR" %0,%0\n" | ||
141 | " j 3f\n" | ||
142 | "1: la %4,255(%1)\n" /* ptr + 255 */ | ||
143 | " "LHI" %3,-4096\n" | ||
144 | " nr %4,%3\n" /* (ptr + 255) & -4096UL */ | ||
145 | " "SLR" %4,%1\n" | ||
146 | " "CLR" %0,%4\n" /* copy crosses next page boundary? */ | ||
147 | " jnh 3f\n" | ||
148 | "2: mvcs 0(%4,%1),0(%2),%3\n" | ||
149 | " "SLR" %0,%4\n" | ||
150 | "3:\n" | ||
151 | EX_TABLE(0b,1b) EX_TABLE(2b,3b) | ||
152 | : "+a" (size), "+a" (ptr), "+a" (x), "+a" (tmp1), "=a" (tmp2) | ||
153 | : : "cc", "memory"); | ||
154 | return size; | ||
155 | } | 118 | } |
156 | 119 | ||
157 | size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) | 120 | size_t copy_in_user_std(size_t size, void __user *to, const void __user *from) |
@@ -343,10 +306,10 @@ int futex_atomic_cmpxchg(int __user *uaddr, int oldval, int newval) | |||
343 | } | 306 | } |
344 | 307 | ||
345 | struct uaccess_ops uaccess_std = { | 308 | struct uaccess_ops uaccess_std = { |
346 | .copy_from_user = copy_from_user_std, | 309 | .copy_from_user = copy_from_user_std_check, |
347 | .copy_from_user_small = copy_from_user_std_small, | 310 | .copy_from_user_small = copy_from_user_std, |
348 | .copy_to_user = copy_to_user_std, | 311 | .copy_to_user = copy_to_user_std_check, |
349 | .copy_to_user_small = copy_to_user_std_small, | 312 | .copy_to_user_small = copy_to_user_std, |
350 | .copy_in_user = copy_in_user_std, | 313 | .copy_in_user = copy_in_user_std, |
351 | .clear_user = clear_user_std, | 314 | .clear_user = clear_user_std, |
352 | .strnlen_user = strnlen_user_std, | 315 | .strnlen_user = strnlen_user_std, |
diff --git a/arch/s390/mm/extmem.c b/arch/s390/mm/extmem.c index 226275d5c4f6..9e9bc48463a5 100644 --- a/arch/s390/mm/extmem.c +++ b/arch/s390/mm/extmem.c | |||
@@ -14,12 +14,13 @@ | |||
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/module.h> | 15 | #include <linux/module.h> |
16 | #include <linux/bootmem.h> | 16 | #include <linux/bootmem.h> |
17 | #include <linux/ctype.h> | ||
17 | #include <asm/page.h> | 18 | #include <asm/page.h> |
18 | #include <asm/ebcdic.h> | 19 | #include <asm/ebcdic.h> |
19 | #include <asm/errno.h> | 20 | #include <asm/errno.h> |
20 | #include <asm/extmem.h> | 21 | #include <asm/extmem.h> |
21 | #include <asm/cpcmd.h> | 22 | #include <asm/cpcmd.h> |
22 | #include <linux/ctype.h> | 23 | #include <asm/setup.h> |
23 | 24 | ||
24 | #define DCSS_DEBUG /* Debug messages on/off */ | 25 | #define DCSS_DEBUG /* Debug messages on/off */ |
25 | 26 | ||
@@ -77,15 +78,11 @@ struct dcss_segment { | |||
77 | int segcnt; | 78 | int segcnt; |
78 | }; | 79 | }; |
79 | 80 | ||
80 | static DEFINE_SPINLOCK(dcss_lock); | 81 | static DEFINE_MUTEX(dcss_lock); |
81 | static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list); | 82 | static struct list_head dcss_list = LIST_HEAD_INIT(dcss_list); |
82 | static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", | 83 | static char *segtype_string[] = { "SW", "EW", "SR", "ER", "SN", "EN", "SC", |
83 | "EW/EN-MIXED" }; | 84 | "EW/EN-MIXED" }; |
84 | 85 | ||
85 | extern struct { | ||
86 | unsigned long addr, size, type; | ||
87 | } memory_chunk[MEMORY_CHUNKS]; | ||
88 | |||
89 | /* | 86 | /* |
90 | * Create the 8 bytes, ebcdic VM segment name from | 87 | * Create the 8 bytes, ebcdic VM segment name from |
91 | * an ascii name. | 88 | * an ascii name. |
@@ -117,7 +114,7 @@ segment_by_name (char *name) | |||
117 | struct list_head *l; | 114 | struct list_head *l; |
118 | struct dcss_segment *tmp, *retval = NULL; | 115 | struct dcss_segment *tmp, *retval = NULL; |
119 | 116 | ||
120 | assert_spin_locked(&dcss_lock); | 117 | BUG_ON(!mutex_is_locked(&dcss_lock)); |
121 | dcss_mkname (name, dcss_name); | 118 | dcss_mkname (name, dcss_name); |
122 | list_for_each (l, &dcss_list) { | 119 | list_for_each (l, &dcss_list) { |
123 | tmp = list_entry (l, struct dcss_segment, list); | 120 | tmp = list_entry (l, struct dcss_segment, list); |
@@ -249,8 +246,8 @@ segment_overlaps_storage(struct dcss_segment *seg) | |||
249 | { | 246 | { |
250 | int i; | 247 | int i; |
251 | 248 | ||
252 | for (i=0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { | 249 | for (i = 0; i < MEMORY_CHUNKS && memory_chunk[i].size > 0; i++) { |
253 | if (memory_chunk[i].type != 0) | 250 | if (memory_chunk[i].type != CHUNK_READ_WRITE) |
254 | continue; | 251 | continue; |
255 | if ((memory_chunk[i].addr >> 20) > (seg->end >> 20)) | 252 | if ((memory_chunk[i].addr >> 20) > (seg->end >> 20)) |
256 | continue; | 253 | continue; |
@@ -272,7 +269,7 @@ segment_overlaps_others (struct dcss_segment *seg) | |||
272 | struct list_head *l; | 269 | struct list_head *l; |
273 | struct dcss_segment *tmp; | 270 | struct dcss_segment *tmp; |
274 | 271 | ||
275 | assert_spin_locked(&dcss_lock); | 272 | BUG_ON(!mutex_is_locked(&dcss_lock)); |
276 | list_for_each(l, &dcss_list) { | 273 | list_for_each(l, &dcss_list) { |
277 | tmp = list_entry(l, struct dcss_segment, list); | 274 | tmp = list_entry(l, struct dcss_segment, list); |
278 | if ((tmp->start_addr >> 20) > (seg->end >> 20)) | 275 | if ((tmp->start_addr >> 20) > (seg->end >> 20)) |
@@ -429,7 +426,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, | |||
429 | if (!MACHINE_IS_VM) | 426 | if (!MACHINE_IS_VM) |
430 | return -ENOSYS; | 427 | return -ENOSYS; |
431 | 428 | ||
432 | spin_lock (&dcss_lock); | 429 | mutex_lock(&dcss_lock); |
433 | seg = segment_by_name (name); | 430 | seg = segment_by_name (name); |
434 | if (seg == NULL) | 431 | if (seg == NULL) |
435 | rc = __segment_load (name, do_nonshared, addr, end); | 432 | rc = __segment_load (name, do_nonshared, addr, end); |
@@ -444,7 +441,7 @@ segment_load (char *name, int do_nonshared, unsigned long *addr, | |||
444 | rc = -EPERM; | 441 | rc = -EPERM; |
445 | } | 442 | } |
446 | } | 443 | } |
447 | spin_unlock (&dcss_lock); | 444 | mutex_unlock(&dcss_lock); |
448 | return rc; | 445 | return rc; |
449 | } | 446 | } |
450 | 447 | ||
@@ -467,7 +464,7 @@ segment_modify_shared (char *name, int do_nonshared) | |||
467 | unsigned long dummy; | 464 | unsigned long dummy; |
468 | int dcss_command, rc, diag_cc; | 465 | int dcss_command, rc, diag_cc; |
469 | 466 | ||
470 | spin_lock (&dcss_lock); | 467 | mutex_lock(&dcss_lock); |
471 | seg = segment_by_name (name); | 468 | seg = segment_by_name (name); |
472 | if (seg == NULL) { | 469 | if (seg == NULL) { |
473 | rc = -EINVAL; | 470 | rc = -EINVAL; |
@@ -508,7 +505,7 @@ segment_modify_shared (char *name, int do_nonshared) | |||
508 | &dummy, &dummy); | 505 | &dummy, &dummy); |
509 | kfree(seg); | 506 | kfree(seg); |
510 | out_unlock: | 507 | out_unlock: |
511 | spin_unlock(&dcss_lock); | 508 | mutex_unlock(&dcss_lock); |
512 | return rc; | 509 | return rc; |
513 | } | 510 | } |
514 | 511 | ||
@@ -526,7 +523,7 @@ segment_unload(char *name) | |||
526 | if (!MACHINE_IS_VM) | 523 | if (!MACHINE_IS_VM) |
527 | return; | 524 | return; |
528 | 525 | ||
529 | spin_lock(&dcss_lock); | 526 | mutex_lock(&dcss_lock); |
530 | seg = segment_by_name (name); | 527 | seg = segment_by_name (name); |
531 | if (seg == NULL) { | 528 | if (seg == NULL) { |
532 | PRINT_ERR ("could not find segment %s in segment_unload, " | 529 | PRINT_ERR ("could not find segment %s in segment_unload, " |
@@ -540,7 +537,7 @@ segment_unload(char *name) | |||
540 | kfree(seg); | 537 | kfree(seg); |
541 | } | 538 | } |
542 | out_unlock: | 539 | out_unlock: |
543 | spin_unlock(&dcss_lock); | 540 | mutex_unlock(&dcss_lock); |
544 | } | 541 | } |
545 | 542 | ||
546 | /* | 543 | /* |
@@ -559,12 +556,13 @@ segment_save(char *name) | |||
559 | if (!MACHINE_IS_VM) | 556 | if (!MACHINE_IS_VM) |
560 | return; | 557 | return; |
561 | 558 | ||
562 | spin_lock(&dcss_lock); | 559 | mutex_lock(&dcss_lock); |
563 | seg = segment_by_name (name); | 560 | seg = segment_by_name (name); |
564 | 561 | ||
565 | if (seg == NULL) { | 562 | if (seg == NULL) { |
566 | PRINT_ERR ("could not find segment %s in segment_save, please report to linux390@de.ibm.com\n",name); | 563 | PRINT_ERR("could not find segment %s in segment_save, please " |
567 | return; | 564 | "report to linux390@de.ibm.com\n", name); |
565 | goto out; | ||
568 | } | 566 | } |
569 | 567 | ||
570 | startpfn = seg->start_addr >> PAGE_SHIFT; | 568 | startpfn = seg->start_addr >> PAGE_SHIFT; |
@@ -591,7 +589,7 @@ segment_save(char *name) | |||
591 | goto out; | 589 | goto out; |
592 | } | 590 | } |
593 | out: | 591 | out: |
594 | spin_unlock(&dcss_lock); | 592 | mutex_unlock(&dcss_lock); |
595 | } | 593 | } |
596 | 594 | ||
597 | EXPORT_SYMBOL(segment_load); | 595 | EXPORT_SYMBOL(segment_load); |
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c index 1c323bbfda91..cd85e34d8703 100644 --- a/arch/s390/mm/fault.c +++ b/arch/s390/mm/fault.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
32 | #include <asm/pgtable.h> | 32 | #include <asm/pgtable.h> |
33 | #include <asm/kdebug.h> | 33 | #include <asm/kdebug.h> |
34 | #include <asm/s390_ext.h> | ||
34 | 35 | ||
35 | #ifndef CONFIG_64BIT | 36 | #ifndef CONFIG_64BIT |
36 | #define __FAIL_ADDR_MASK 0x7ffff000 | 37 | #define __FAIL_ADDR_MASK 0x7ffff000 |
@@ -394,6 +395,7 @@ void do_dat_exception(struct pt_regs *regs, unsigned long error_code) | |||
394 | /* | 395 | /* |
395 | * 'pfault' pseudo page faults routines. | 396 | * 'pfault' pseudo page faults routines. |
396 | */ | 397 | */ |
398 | static ext_int_info_t ext_int_pfault; | ||
397 | static int pfault_disable = 0; | 399 | static int pfault_disable = 0; |
398 | 400 | ||
399 | static int __init nopfault(char *str) | 401 | static int __init nopfault(char *str) |
@@ -422,7 +424,7 @@ int pfault_init(void) | |||
422 | __PF_RES_FIELD }; | 424 | __PF_RES_FIELD }; |
423 | int rc; | 425 | int rc; |
424 | 426 | ||
425 | if (pfault_disable) | 427 | if (!MACHINE_IS_VM || pfault_disable) |
426 | return -1; | 428 | return -1; |
427 | asm volatile( | 429 | asm volatile( |
428 | " diag %1,%0,0x258\n" | 430 | " diag %1,%0,0x258\n" |
@@ -440,7 +442,7 @@ void pfault_fini(void) | |||
440 | pfault_refbk_t refbk = | 442 | pfault_refbk_t refbk = |
441 | { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; | 443 | { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL }; |
442 | 444 | ||
443 | if (pfault_disable) | 445 | if (!MACHINE_IS_VM || pfault_disable) |
444 | return; | 446 | return; |
445 | __ctl_clear_bit(0,9); | 447 | __ctl_clear_bit(0,9); |
446 | asm volatile( | 448 | asm volatile( |
@@ -500,5 +502,25 @@ pfault_interrupt(__u16 error_code) | |||
500 | set_tsk_need_resched(tsk); | 502 | set_tsk_need_resched(tsk); |
501 | } | 503 | } |
502 | } | 504 | } |
503 | #endif | ||
504 | 505 | ||
506 | void __init pfault_irq_init(void) | ||
507 | { | ||
508 | if (!MACHINE_IS_VM) | ||
509 | return; | ||
510 | |||
511 | /* | ||
512 | * Try to get pfault pseudo page faults going. | ||
513 | */ | ||
514 | if (register_early_external_interrupt(0x2603, pfault_interrupt, | ||
515 | &ext_int_pfault) != 0) | ||
516 | panic("Couldn't request external interrupt 0x2603"); | ||
517 | |||
518 | if (pfault_init() == 0) | ||
519 | return; | ||
520 | |||
521 | /* Tough luck, no pfault. */ | ||
522 | pfault_disable = 1; | ||
523 | unregister_early_external_interrupt(0x2603, pfault_interrupt, | ||
524 | &ext_int_pfault); | ||
525 | } | ||
526 | #endif | ||