aboutsummaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
Diffstat (limited to 'arch')
-rw-r--r--arch/s390/kernel/entry.S102
-rw-r--r--arch/s390/kernel/entry64.S97
-rw-r--r--arch/s390/kernel/process.c46
-rw-r--r--arch/s390/kernel/setup.c13
-rw-r--r--arch/s390/kernel/smp.c13
5 files changed, 215 insertions, 56 deletions
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index c0e09b33feb..5b262b5d869 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -7,6 +7,7 @@
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Hartmut Penner (hp@de.ibm.com),
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
*/
#include <linux/sys.h>
@@ -49,9 +50,9 @@ SP_ILC = STACK_FRAME_OVERHEAD + __PT_ILC
SP_TRAP = STACK_FRAME_OVERHEAD + __PT_TRAP
SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \
_TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
@@ -121,7 +122,11 @@ STACK_SIZE = 1 << STACK_SHIFT
bz BASED(stack_overflow)
3:
#endif
-2: s %r15,BASED(.Lc_spsize) # make room for registers & psw
+2:
+ .endm
+
+ .macro CREATE_STACK_FRAME psworg,savearea
+ s %r15,BASED(.Lc_spsize) # make room for registers & psw
mvc SP_PSW(8,%r15),0(%r12) # move user PSW to stack
la %r12,\psworg
st %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
@@ -161,6 +166,13 @@ __switch_to_base:
be __switch_to_noper-__switch_to_base(%r1) # we got away w/o bashing TLB's
lctl %c9,%c11,__THREAD_per(%r3) # Nope we didn't
__switch_to_noper:
+ l %r4,__THREAD_info(%r2) # get thread_info of prev
+ tm __TI_flags+3(%r4),_TIF_MCCK_PENDING # machine check pending?
+ bz __switch_to_no_mcck-__switch_to_base(%r1)
+ ni __TI_flags+3(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
+ l %r4,__THREAD_info(%r3) # get thread_info of next
+ oi __TI_flags+3(%r4),_TIF_MCCK_PENDING # set it in next
+__switch_to_no_mcck:
stm %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
st %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
l %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
@@ -185,6 +197,7 @@ system_call:
sysc_saveall:
SAVE_ALL_BASE __LC_SAVE_AREA
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
lh %r7,0x8a # get svc number from lowcore
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
sysc_vtime:
@@ -234,6 +247,8 @@ sysc_work_loop:
# One of the work bits is on. Find out which one.
#
sysc_work:
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+ bo BASED(sysc_mcck_pending)
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
bo BASED(sysc_reschedule)
tm __TI_flags+3(%r9),_TIF_SIGPENDING
@@ -253,6 +268,14 @@ sysc_reschedule:
br %r1 # call scheduler
#
+# _TIF_MCCK_PENDING is set, call handler
+#
+sysc_mcck_pending:
+ l %r1,BASED(.Ls390_handle_mcck)
+ la %r14,BASED(sysc_work_loop)
+ br %r1 # TIF bit will be cleared by handler
+
+#
# _TIF_SIGPENDING is set, call do_signal
#
sysc_sigpending:
@@ -430,6 +453,7 @@ pgm_check_handler:
tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
bnz BASED(pgm_per) # got per exception -> special case
SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(pgm_no_vtime)
@@ -468,6 +492,7 @@ pgm_per:
#
pgm_per_std:
SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(pgm_no_vtime2)
@@ -493,6 +518,7 @@ pgm_no_vtime2:
#
pgm_svcper:
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(pgm_no_vtime3)
@@ -521,6 +547,7 @@ io_int_handler:
stck __LC_INT_CLOCK
SAVE_ALL_BASE __LC_SAVE_AREA+16
SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+16,0
+ CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+16
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(io_no_vtime)
@@ -578,9 +605,11 @@ io_work:
lr %r15,%r1
#
# One of the work bits is on. Find out which one.
-# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
+# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING
#
io_work_loop:
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+ bo BASED(io_mcck_pending)
tm __TI_flags+3(%r9),_TIF_NEED_RESCHED
bo BASED(io_reschedule)
tm __TI_flags+3(%r9),_TIF_SIGPENDING
@@ -588,6 +617,14 @@ io_work_loop:
b BASED(io_leave)
#
+# _TIF_MCCK_PENDING is set, call handler
+#
+io_mcck_pending:
+ l %r1,BASED(.Ls390_handle_mcck)
+ l %r14,BASED(io_work_loop)
+ br %r1 # TIF bit will be cleared by handler
+
+#
# _TIF_NEED_RESCHED is set, call schedule
#
io_reschedule:
@@ -621,6 +658,7 @@ ext_int_handler:
stck __LC_INT_CLOCK
SAVE_ALL_BASE __LC_SAVE_AREA+16
SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16,0
+ CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+16
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
bz BASED(ext_no_vtime)
@@ -642,19 +680,62 @@ ext_no_vtime:
.globl mcck_int_handler
mcck_int_handler:
- STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer
+ lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs
SAVE_ALL_BASE __LC_SAVE_AREA+32
- SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32,0
+ la %r12,__LC_MCK_OLD_PSW
+ tm __LC_MCCK_CODE,0x80 # system damage?
+ bo BASED(mcck_int_main) # yes -> rest of mcck code invalid
+ tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid?
+ bo BASED(0f)
+ spt __LC_LAST_UPDATE_TIMER # revalidate cpu timer
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER
+0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ bno BASED(mcck_no_vtime) # no -> skip cleanup critical
+ tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
bz BASED(mcck_no_vtime)
UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
mcck_no_vtime:
#endif
+0:
+ tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
+ bno BASED(mcck_int_main) # no -> skip cleanup critical
+ tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+ bnz BASED(mcck_int_main) # from user -> load async stack
+ clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_end)
+ bhe BASED(mcck_int_main)
+ clc __LC_MCK_OLD_PSW+4(4),BASED(.Lcritical_start)
+ bl BASED(mcck_int_main)
+ l %r14,BASED(.Lcleanup_critical)
+ basr %r14,%r14
+mcck_int_main:
+ l %r14,__LC_PANIC_STACK # are we already on the panic stack?
+ slr %r14,%r15
+ sra %r14,PAGE_SHIFT
+ be BASED(0f)
+ l %r15,__LC_PANIC_STACK # load panic stack
+0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+32
+ l %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ la %r2,SP_PTREGS(%r15) # load pt_regs
l %r1,BASED(.Ls390_mcck)
- basr %r14,%r1 # call machine check handler
+ basr %r14,%r1 # call machine check handler
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ bno BASED(mcck_return)
+ l %r1,__LC_KERNEL_STACK # switch to kernel stack
+ s %r1,BASED(.Lc_spsize)
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lr %r15,%r1
+ stosm __SF_EMPTY(%r15),0x04 # turn dat on
+ tm __TI_flags+3(%r9),_TIF_MCCK_PENDING
+ bno BASED(mcck_return)
+ l %r1,BASED(.Ls390_handle_mcck)
+ basr %r14,%r1 # call machine check handler
mcck_return:
RESTORE_ALL 0
@@ -742,7 +823,7 @@ cleanup_critical:
clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop)
bl BASED(0f)
clc 4(4,%r12),BASED(cleanup_table_sysc_work_loop+4)
- bl BASED(cleanup_sysc_leave)
+ bl BASED(cleanup_sysc_return)
0:
br %r14
@@ -760,6 +841,7 @@ cleanup_system_call:
mvc __LC_SAVE_AREA(16),__LC_SAVE_AREA+16
0: st %r13,__LC_SAVE_AREA+20
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
st %r15,__LC_SAVE_AREA+28
lh %r7,0x8a
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
@@ -834,6 +916,8 @@ cleanup_sysc_leave_insn:
* Symbol constants
*/
.Ls390_mcck: .long s390_do_machine_check
+.Ls390_handle_mcck:
+ .long s390_handle_mcck
.Ldo_IRQ: .long do_IRQ
.Ldo_extint: .long do_extint
.Ldo_signal: .long do_signal
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 51527ab8c8f..57ca75d0ad7 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -7,6 +7,7 @@
* Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
* Hartmut Penner (hp@de.ibm.com),
* Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
+ * Heiko Carstens <heiko.carstens@de.ibm.com>
*/
#include <linux/sys.h>
@@ -52,9 +53,9 @@ SP_SIZE = STACK_FRAME_OVERHEAD + __PT_SIZE
STACK_SHIFT = PAGE_SHIFT + THREAD_ORDER
STACK_SIZE = 1 << STACK_SHIFT
-_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
+_TIF_WORK_SVC = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING | \
_TIF_RESTART_SVC | _TIF_SINGLE_STEP )
-_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
+_TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED | _TIF_MCCK_PENDING)
#define BASED(name) name-system_call(%r13)
@@ -114,7 +115,11 @@ _TIF_WORK_INT = (_TIF_SIGPENDING | _TIF_NEED_RESCHED)
jz stack_overflow
3:
#endif
-2: aghi %r15,-SP_SIZE # make room for registers & psw
+2:
+ .endm
+
+ .macro CREATE_STACK_FRAME psworg,savearea
+ aghi %r15,-SP_SIZE # make room for registers & psw
mvc SP_PSW(16,%r15),0(%r12) # move user PSW to stack
la %r12,\psworg
stg %r2,SP_ORIG_R2(%r15) # store original content of gpr 2
@@ -152,6 +157,13 @@ __switch_to:
je __switch_to_noper # we got away without bashing TLB's
lctlg %c9,%c11,__THREAD_per(%r3) # Nope we didn't
__switch_to_noper:
+ lg %r4,__THREAD_info(%r2) # get thread_info of prev
+ tm __TI_flags+7(%r4),_TIF_MCCK_PENDING # machine check pending?
+ jz __switch_to_no_mcck
+ ni __TI_flags+7(%r4),255-_TIF_MCCK_PENDING # clear flag in prev
+ lg %r4,__THREAD_info(%r3) # get thread_info of next
+ oi __TI_flags+7(%r4),_TIF_MCCK_PENDING # set it in next
+__switch_to_no_mcck:
stmg %r6,%r15,__SF_GPRS(%r15)# store __switch_to registers of prev task
stg %r15,__THREAD_ksp(%r2) # store kernel stack to prev->tss.ksp
lg %r15,__THREAD_ksp(%r3) # load kernel stack from next->tss.ksp
@@ -176,6 +188,7 @@ system_call:
sysc_saveall:
SAVE_ALL_BASE __LC_SAVE_AREA
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
llgh %r7,__LC_SVC_INT_CODE # get svc number from lowcore
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
sysc_vtime:
@@ -232,6 +245,8 @@ sysc_work_loop:
# One of the work bits is on. Find out which one.
#
sysc_work:
+ tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
+ jo sysc_mcck_pending
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jo sysc_reschedule
tm __TI_flags+7(%r9),_TIF_SIGPENDING
@@ -250,6 +265,13 @@ sysc_reschedule:
jg schedule # return point is sysc_return
#
+# _TIF_MCCK_PENDING is set, call handler
+#
+sysc_mcck_pending:
+ larl %r14,sysc_work_loop
+ jg s390_handle_mcck # TIF bit will be cleared by handler
+
+#
# _TIF_SIGPENDING is set, call do_signal
#
sysc_sigpending:
@@ -474,6 +496,7 @@ pgm_check_handler:
tm __LC_PGM_INT_CODE+1,0x80 # check whether we got a per exception
jnz pgm_per # got per exception -> special case
SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz pgm_no_vtime
@@ -512,6 +535,7 @@ pgm_per:
#
pgm_per_std:
SAVE_ALL __LC_PGM_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_PGM_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz pgm_no_vtime2
@@ -537,6 +561,7 @@ pgm_no_vtime2:
#
pgm_svcper:
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz pgm_no_vtime3
@@ -564,6 +589,7 @@ io_int_handler:
stck __LC_INT_CLOCK
SAVE_ALL_BASE __LC_SAVE_AREA+32
SAVE_ALL __LC_IO_OLD_PSW,__LC_SAVE_AREA+32,0
+ CREATE_STACK_FRAME __LC_IO_OLD_PSW,__LC_SAVE_AREA+32
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz io_no_vtime
@@ -621,9 +647,11 @@ io_work:
lgr %r15,%r1
#
# One of the work bits is on. Find out which one.
-# Checked are: _TIF_SIGPENDING and _TIF_NEED_RESCHED
+# Checked are: _TIF_SIGPENDING, _TIF_NEED_RESCHED and _TIF_MCCK_PENDING
#
io_work_loop:
+ tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
+ jo io_mcck_pending
tm __TI_flags+7(%r9),_TIF_NEED_RESCHED
jo io_reschedule
tm __TI_flags+7(%r9),_TIF_SIGPENDING
@@ -631,6 +659,13 @@ io_work_loop:
j io_leave
#
+# _TIF_MCCK_PENDING is set, call handler
+#
+io_mcck_pending:
+ larl %r14,io_work_loop
+ jg s390_handle_mcck # TIF bit will be cleared by handler
+
+#
# _TIF_NEED_RESCHED is set, call schedule
#
io_reschedule:
@@ -661,6 +696,7 @@ ext_int_handler:
stck __LC_INT_CLOCK
SAVE_ALL_BASE __LC_SAVE_AREA+32
SAVE_ALL __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32,0
+ CREATE_STACK_FRAME __LC_EXT_OLD_PSW,__LC_SAVE_AREA+32
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
tm SP_PSW+1(%r15),0x01 # interrupting from user ?
jz ext_no_vtime
@@ -680,18 +716,60 @@ ext_no_vtime:
*/
.globl mcck_int_handler
mcck_int_handler:
- STORE_TIMER __LC_ASYNC_ENTER_TIMER
+ la %r1,4095 # revalidate r1
+ spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer
+ lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
SAVE_ALL_BASE __LC_SAVE_AREA+64
- SAVE_ALL __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64,0
+ la %r12,__LC_MCK_OLD_PSW
+ tm __LC_MCCK_CODE,0x80 # system damage?
+ jo mcck_int_main # yes -> rest of mcck code invalid
+ tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid?
+ jo 0f
+ spt __LC_LAST_UPDATE_TIMER
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
- tm SP_PSW+1(%r15),0x01 # interrupting from user ?
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
+ mvc __LC_LAST_UPDATE_TIMER(8),__LC_EXIT_TIMER
+0: tm __LC_MCCK_CODE+2,0x08 # mwp of old psw valid?
+ jno mcck_no_vtime # no -> no timer update
+ tm __LC_MCK_OLD_PSW+1,0x01 # interrupting from user ?
jz mcck_no_vtime
UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER
UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
mcck_no_vtime:
#endif
- brasl %r14,s390_do_machine_check
+0:
+ tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
+ jno mcck_int_main # no -> skip cleanup critical
+ tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
+ jnz mcck_int_main # from user -> load kernel stack
+ clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_end)
+ jhe mcck_int_main
+ clc __LC_MCK_OLD_PSW+8(8),BASED(.Lcritical_start)
+ jl mcck_int_main
+ brasl %r14,cleanup_critical
+mcck_int_main:
+ lg %r14,__LC_PANIC_STACK # are we already on the panic stack?
+ slgr %r14,%r15
+ srag %r14,%r14,PAGE_SHIFT
+ jz 0f
+ lg %r15,__LC_PANIC_STACK # load panic stack
+0: CREATE_STACK_FRAME __LC_MCK_OLD_PSW,__LC_SAVE_AREA+64
+ lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
+ la %r2,SP_PTREGS(%r15) # load pt_regs
+ brasl %r14,s390_do_machine_check
+ tm SP_PSW+1(%r15),0x01 # returning to user ?
+ jno mcck_return
+ lg %r1,__LC_KERNEL_STACK # switch to kernel stack
+ aghi %r1,-SP_SIZE
+ mvc SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
+ xc __SF_BACKCHAIN(8,%r1),__SF_BACKCHAIN(%r1) # clear back chain
+ lgr %r15,%r1
+ stosm __SF_EMPTY(%r15),0x04 # turn dat on
+ tm __TI_flags+7(%r9),_TIF_MCCK_PENDING
+ jno mcck_return
+ brasl %r14,s390_handle_mcck
mcck_return:
RESTORE_ALL 0
@@ -775,7 +853,7 @@ cleanup_critical:
clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop)
jl 0f
clc 8(8,%r12),BASED(cleanup_table_sysc_work_loop+8)
- jl cleanup_sysc_leave
+ jl cleanup_sysc_return
0:
br %r14
@@ -793,6 +871,7 @@ cleanup_system_call:
mvc __LC_SAVE_AREA(32),__LC_SAVE_AREA+32
0: stg %r13,__LC_SAVE_AREA+40
SAVE_ALL __LC_SVC_OLD_PSW,__LC_SAVE_AREA,1
+ CREATE_STACK_FRAME __LC_SVC_OLD_PSW,__LC_SAVE_AREA
stg %r15,__LC_SAVE_AREA+56
llgh %r7,__LC_SVC_INT_CODE
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
diff --git a/arch/s390/kernel/process.c b/arch/s390/kernel/process.c
index 7aea25d6e30..9f3dff6c0b7 100644
--- a/arch/s390/kernel/process.c
+++ b/arch/s390/kernel/process.c
@@ -91,13 +91,12 @@ void do_monitor_call(struct pt_regs *regs, long interruption_code)
(void *)(long) smp_processor_id());
}
+extern void s390_handle_mcck(void);
/*
* The idle loop on a S390...
*/
void default_idle(void)
{
- psw_t wait_psw;
- unsigned long reg;
int cpu, rc;
local_irq_disable();
@@ -125,38 +124,17 @@ void default_idle(void)
cpu_die();
#endif
- /*
- * Wait for external, I/O or machine check interrupt and
- * switch off machine check bit after the wait has ended.
- */
- wait_psw.mask = PSW_KERNEL_BITS | PSW_MASK_MCHECK | PSW_MASK_WAIT |
- PSW_MASK_IO | PSW_MASK_EXT;
-#ifndef CONFIG_ARCH_S390X
- asm volatile (
- " basr %0,0\n"
- "0: la %0,1f-0b(%0)\n"
- " st %0,4(%1)\n"
- " oi 4(%1),0x80\n"
- " lpsw 0(%1)\n"
- "1: la %0,2f-1b(%0)\n"
- " st %0,4(%1)\n"
- " oi 4(%1),0x80\n"
- " ni 1(%1),0xf9\n"
- " lpsw 0(%1)\n"
- "2:"
- : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
-#else /* CONFIG_ARCH_S390X */
- asm volatile (
- " larl %0,0f\n"
- " stg %0,8(%1)\n"
- " lpswe 0(%1)\n"
- "0: larl %0,1f\n"
- " stg %0,8(%1)\n"
- " ni 1(%1),0xf9\n"
- " lpswe 0(%1)\n"
- "1:"
- : "=&a" (reg) : "a" (&wait_psw) : "memory", "cc" );
-#endif /* CONFIG_ARCH_S390X */
+ local_mcck_disable();
+ if (test_thread_flag(TIF_MCCK_PENDING)) {
+ local_mcck_enable();
+ local_irq_enable();
+ s390_handle_mcck();
+ return;
+ }
+
+ /* Wait for external, I/O or machine check interrupt. */
+ __load_psw_mask(PSW_KERNEL_BITS | PSW_MASK_WAIT |
+ PSW_MASK_IO | PSW_MASK_EXT);
}
void cpu_idle(void)
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index df83215beac..eb7be0ad717 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -414,7 +414,8 @@ setup_lowcore(void)
lc->program_new_psw.mask = PSW_KERNEL_BITS;
lc->program_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long)pgm_check_handler;
- lc->mcck_new_psw.mask = PSW_KERNEL_BITS;
+ lc->mcck_new_psw.mask =
+ PSW_KERNEL_BITS & ~PSW_MASK_MCHECK & ~PSW_MASK_DAT;
lc->mcck_new_psw.addr =
PSW_ADDR_AMODE | (unsigned long) mcck_int_handler;
lc->io_new_psw.mask = PSW_KERNEL_BITS;
@@ -424,12 +425,18 @@ setup_lowcore(void)
lc->kernel_stack = ((unsigned long) &init_thread_union) + THREAD_SIZE;
lc->async_stack = (unsigned long)
__alloc_bootmem(ASYNC_SIZE, ASYNC_SIZE, 0) + ASYNC_SIZE;
-#ifdef CONFIG_CHECK_STACK
lc->panic_stack = (unsigned long)
__alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0) + PAGE_SIZE;
-#endif
lc->current_task = (unsigned long) init_thread_union.thread_info.task;
lc->thread_info = (unsigned long) &init_thread_union;
+#ifndef CONFIG_ARCH_S390X
+ if (MACHINE_HAS_IEEE) {
+ lc->extended_save_area_addr = (__u32)
+ __alloc_bootmem(PAGE_SIZE, PAGE_SIZE, 0);
+ /* enable extended save area */
+ ctl_set_bit(14, 29);
+ }
+#endif
#ifdef CONFIG_ARCH_S390X
if (MACHINE_HAS_DIAG44)
lc->diag44_opcode = 0x83000044;
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 93c71fef99d..50c335067cf 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -773,13 +773,24 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
*(lowcore_ptr[i]) = S390_lowcore;
lowcore_ptr[i]->async_stack = stack + (ASYNC_SIZE);
-#ifdef CONFIG_CHECK_STACK
stack = __get_free_pages(GFP_KERNEL,0);
if (stack == 0ULL)
panic("smp_boot_cpus failed to allocate memory\n");
lowcore_ptr[i]->panic_stack = stack + (PAGE_SIZE);
+#ifndef __s390x__
+ if (MACHINE_HAS_IEEE) {
+ lowcore_ptr[i]->extended_save_area_addr =
+ (__u32) __get_free_pages(GFP_KERNEL,0);
+ if (lowcore_ptr[i]->extended_save_area_addr == 0)
+ panic("smp_boot_cpus failed to "
+ "allocate memory\n");
+ }
#endif
}
+#ifndef __s390x__
+ if (MACHINE_HAS_IEEE)
+ ctl_set_bit(14, 29); /* enable extended save area */
+#endif
set_prefix((u32)(unsigned long) lowcore_ptr[smp_processor_id()]);
for_each_cpu(cpu)