summary refs log tree commit diff
path: root/arch/s390/kernel/entry.S
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2010-05-17 10:00:02 +0200
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-05-17 10:00:15 +0200
commit6a2df3a87276cdc08fd87070d09ea18d1fb9d622 (patch)
tree384b646d0a826ab5c2bafa63e9bea4a057815fe2 /arch/s390/kernel/entry.S
parent43d399d2ab7e96cb8d952d0ba4e9131587b7c8b9 (diff)
downloadlinux-6a2df3a87276cdc08fd87070d09ea18d1fb9d622.tar.gz
[S390] improve irq tracing code in entry[64].S
The system call path in entry[64].S is run with interrupts enabled.
Remove the irq tracing check from the system call exit code. If a
program check interrupted a context enabled for interrupts do a
call to trace_irq_off_caller in the program check handler before
branching to the system call exit code.
Restructure the system call and io interrupt return code to avoid
avoid the lpsw[e] to disable machine checks.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/entry.S')
-rw-r--r--arch/s390/kernel/entry.S205
1 files changed, 91 insertions, 114 deletions
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S
index ffebfb64b913..07d849995dac 100644
--- a/arch/s390/kernel/entry.S
+++ b/arch/s390/kernel/entry.S
@@ -73,21 +73,24 @@ STACK_SIZE  = 1 << STACK_SHIFT
 	basr	%r14,%r1
 	.endm
 
-	.macro	TRACE_IRQS_CHECK
-	basr	%r2,%r0
+	.macro	TRACE_IRQS_CHECK_ON
 	tm	SP_PSW(%r15),0x03	# irqs enabled?
-	jz	0f
-	l	%r1,BASED(.Ltrace_irq_on_caller)
-	basr	%r14,%r1
-	j	1f
-0:	l	%r1,BASED(.Ltrace_irq_off_caller)
-	basr	%r14,%r1
-1:
+	bz	BASED(0f)
+	TRACE_IRQS_ON
+0:
+	.endm
+
+	.macro	TRACE_IRQS_CHECK_OFF
+	tm	SP_PSW(%r15),0x03	# irqs enabled?
+	bz	BASED(0f)
+	TRACE_IRQS_OFF
+0:
 	.endm
 #else
 #define TRACE_IRQS_ON
 #define TRACE_IRQS_OFF
-#define TRACE_IRQS_CHECK
+#define TRACE_IRQS_CHECK_ON
+#define TRACE_IRQS_CHECK_OFF
 #endif
 
 #ifdef CONFIG_LOCKDEP
@@ -273,33 +276,14 @@ sysc_do_restart:
 	st	%r2,SP_R2(%r15)   # store return value (change R2 on stack)
 
 sysc_return:
+	LOCKDEP_SYS_EXIT
+sysc_tif:
 	tm	__TI_flags+3(%r9),_TIF_WORK_SVC
 	bnz	BASED(sysc_work)  # there is work to do (signals etc.)
 sysc_restore:
-#ifdef CONFIG_TRACE_IRQFLAGS
-	la	%r1,BASED(sysc_restore_trace_psw_addr)
-	l	%r1,0(%r1)
-	lpsw	0(%r1)
-sysc_restore_trace:
-	TRACE_IRQS_CHECK
-	LOCKDEP_SYS_EXIT
-#endif
-sysc_leave:
 	RESTORE_ALL __LC_RETURN_PSW,1
 sysc_done:
 
-#ifdef CONFIG_TRACE_IRQFLAGS
-sysc_restore_trace_psw_addr:
-	.long sysc_restore_trace_psw
-
-	.section .data,"aw",@progbits
-	.align	8
-	.globl	sysc_restore_trace_psw
-sysc_restore_trace_psw:
-	.long	0, sysc_restore_trace + 0x80000000
-	.previous
-#endif
-
 #
 # There is work to do, but first we need to check if we return to userspace.
 #
@@ -310,7 +294,7 @@ sysc_work:
 #
 # One of the work bits is on. Find out which one.
 #
-sysc_work_loop:
+sysc_work_tif:
 	tm	__TI_flags+3(%r9),_TIF_MCCK_PENDING
 	bo	BASED(sysc_mcck_pending)
 	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
@@ -330,7 +314,7 @@ sysc_work_loop:
 #
 sysc_reschedule:
 	l	%r1,BASED(.Lschedule)
-	la	%r14,BASED(sysc_work_loop)
+	la	%r14,BASED(sysc_return)
 	br	%r1			# call scheduler
 
 #
@@ -338,7 +322,7 @@ sysc_reschedule:
 #
 sysc_mcck_pending:
 	l	%r1,BASED(.Ls390_handle_mcck)
-	la	%r14,BASED(sysc_work_loop)
+	la	%r14,BASED(sysc_return)
 	br	%r1			# TIF bit will be cleared by handler
 
 #
@@ -353,7 +337,7 @@ sysc_sigpending:
 	bo	BASED(sysc_restart)
 	tm	__TI_flags+3(%r9),_TIF_SINGLE_STEP
 	bo	BASED(sysc_singlestep)
-	b	BASED(sysc_work_loop)
+	b	BASED(sysc_return)
 
 #
 # _TIF_NOTIFY_RESUME is set, call do_notify_resume
@@ -361,7 +345,7 @@ sysc_sigpending:
 sysc_notify_resume:
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	l	%r1,BASED(.Ldo_notify_resume)
-	la	%r14,BASED(sysc_work_loop)
+	la	%r14,BASED(sysc_return)
 	br	%r1			# call do_notify_resume
 
 
@@ -384,7 +368,7 @@ sysc_singlestep:
 	mvi	SP_SVCNR+1(%r15),0xff
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	l	%r1,BASED(.Lhandle_per)	# load adr. of per handler
-	la	%r14,BASED(sysc_work_loop)	# load adr. of system return
+	la	%r14,BASED(sysc_return)	# load adr. of system return
 	br	%r1			# branch to do_single_step
 
 #
@@ -456,11 +440,13 @@ kernel_execve:
 	br	%r14
 	# execve succeeded.
 0:	stnsm	__SF_EMPTY(%r15),0xfc	# disable interrupts
+	TRACE_IRQS_OFF
 	l	%r15,__LC_KERNEL_STACK	# load ksp
 	s	%r15,BASED(.Lc_spsize)	# make room for registers & psw
 	l	%r9,__LC_THREAD_INFO
 	mvc	SP_PTREGS(__PT_SIZE,%r15),0(%r12)	# copy pt_regs
 	xc	__SF_BACKCHAIN(4,%r15),__SF_BACKCHAIN(%r15)
+	TRACE_IRQS_ON
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	l	%r1,BASED(.Lexecve_tail)
 	basr	%r14,%r1
@@ -497,8 +483,8 @@ pgm_check_handler:
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime:
+	TRACE_IRQS_CHECK_OFF
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
-	TRACE_IRQS_OFF
 	l	%r3,__LC_PGM_ILC	# load program interruption code
 	la	%r8,0x7f
 	nr	%r8,%r3
@@ -507,8 +493,10 @@ pgm_do_call:
 	sll	%r8,2
 	l	%r7,0(%r8,%r7)		# load address of handler routine
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
-	la	%r14,BASED(sysc_return)
-	br	%r7			# branch to interrupt-handler
+	basr	%r14,%r7		# branch to interrupt-handler
+pgm_exit:
+	TRACE_IRQS_CHECK_ON
+	b	BASED(sysc_return)
 
 #
 # handle per exception
@@ -535,19 +523,19 @@ pgm_per_std:
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_SYNC_ENTER_TIMER
 pgm_no_vtime2:
+	TRACE_IRQS_CHECK_OFF
 	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
-	TRACE_IRQS_OFF
 	l	%r1,__TI_task(%r9)
+	tm	SP_PSW+1(%r15),0x01	# kernel per event ?
+	bz	BASED(kernel_per)
 	mvc	__THREAD_per+__PER_atmid(2,%r1),__LC_PER_ATMID
 	mvc	__THREAD_per+__PER_address(4,%r1),__LC_PER_ADDRESS
 	mvc	__THREAD_per+__PER_access_id(1,%r1),__LC_PER_ACCESS_ID
 	oi	__TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
-	tm	SP_PSW+1(%r15),0x01	# kernel per event ?
-	bz	BASED(kernel_per)
 	l	%r3,__LC_PGM_ILC	# load program interruption code
 	la	%r8,0x7f
 	nr	%r8,%r3 		# clear per-event-bit and ilc
-	be	BASED(sysc_return)	# only per or per+check ?
+	be	BASED(pgm_exit)		# only per or per+check ?
 	b	BASED(pgm_do_call)
 
 #
@@ -568,8 +556,8 @@ pgm_svcper:
 	mvc	__THREAD_per+__PER_access_id(1,%r8),__LC_PER_ACCESS_ID
 	oi	__TI_flags+3(%r9),_TIF_SINGLE_STEP # set TIF_SINGLE_STEP
 	TRACE_IRQS_ON
-	lm	%r2,%r6,SP_R2(%r15)	# load svc arguments
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
+	lm	%r2,%r6,SP_R2(%r15)	# load svc arguments
 	b	BASED(sysc_do_svc)
 
 #
@@ -580,8 +568,8 @@ kernel_per:
 	mvi	SP_SVCNR+1(%r15),0xff
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	l	%r1,BASED(.Lhandle_per)	# load adr. of per handler
-	la	%r14,BASED(sysc_restore)# load adr. of system return
-	br	%r1			# branch to do_single_step
+	basr	%r14,%r1		# branch to do_single_step
+	b	BASED(pgm_exit)
 
 /*
  * IO interrupt handler routine
@@ -600,39 +588,21 @@ io_int_handler:
 	UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
 	mvc	__LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER
 io_no_vtime:
-	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	TRACE_IRQS_OFF
+	l	%r9,__LC_THREAD_INFO	# load pointer to thread_info struct
 	l	%r1,BASED(.Ldo_IRQ)	# load address of do_IRQ
 	la	%r2,SP_PTREGS(%r15)	# address of register-save area
 	basr	%r14,%r1		# branch to standard irq handler
 io_return:
+	LOCKDEP_SYS_EXIT
+	TRACE_IRQS_ON
+io_tif:
 	tm	__TI_flags+3(%r9),_TIF_WORK_INT
 	bnz	BASED(io_work)		# there is work to do (signals etc.)
 io_restore:
-#ifdef CONFIG_TRACE_IRQFLAGS
-	la	%r1,BASED(io_restore_trace_psw_addr)
-	l	%r1,0(%r1)
-	lpsw	0(%r1)
-io_restore_trace:
-	TRACE_IRQS_CHECK
-	LOCKDEP_SYS_EXIT
-#endif
-io_leave:
 	RESTORE_ALL __LC_RETURN_PSW,0
 io_done:
 
-#ifdef CONFIG_TRACE_IRQFLAGS
-io_restore_trace_psw_addr:
-	.long io_restore_trace_psw
-
-	.section .data,"aw",@progbits
-	.align	8
-	.globl	io_restore_trace_psw
-io_restore_trace_psw:
-	.long	0, io_restore_trace + 0x80000000
-	.previous
-#endif
-
 #
 # There is work todo, find out in which context we have been interrupted:
 # 1) if we return to user space we can do all _TIF_WORK_INT work
@@ -647,19 +617,23 @@ io_work:
 	# check for preemptive scheduling
 	icm	%r0,15,__TI_precount(%r9)
 	bnz	BASED(io_restore)	# preemption disabled
+	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
+	bno	BASED(io_restore)
 	# switch to kernel stack
 	l	%r1,SP_R15(%r15)
 	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
-io_resume_loop:
+	# TRACE_IRQS_ON already done at io_return, call
+	# TRACE_IRQS_OFF to keep things symmetrical
+	TRACE_IRQS_OFF
 	l	%r1,BASED(.Lpreempt_schedule_irq)
-	la	%r14,BASED(io_resume_loop)
-	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
-	bor	%r1			# call preempt_schedule_irq
-#endif
+	basr	%r14,%r1		# call preempt_schedule_irq
+	b	BASED(io_return)
+#else
 	b	BASED(io_restore)
+#endif
 
 #
 # Need to do work before returning to userspace, switch to kernel stack
@@ -670,12 +644,13 @@ io_work_user:
 	mvc	SP_PTREGS(__PT_SIZE,%r1),SP_PTREGS(%r15)
 	xc	__SF_BACKCHAIN(4,%r1),__SF_BACKCHAIN(%r1) # clear back chain
 	lr	%r15,%r1
+
 #
 # One of the work bits is on. Find out which one.
 # Checked are: _TIF_SIGPENDING, _TIF_NOTIFY_RESUME, _TIF_NEED_RESCHED
 #		and _TIF_MCCK_PENDING
 #
-io_work_loop:
+io_work_tif:
 	tm	__TI_flags+3(%r9),_TIF_MCCK_PENDING
 	bo	BASED(io_mcck_pending)
 	tm	__TI_flags+3(%r9),_TIF_NEED_RESCHED
@@ -690,47 +665,49 @@ io_work_loop:
 # _TIF_MCCK_PENDING is set, call handler
 #
 io_mcck_pending:
+	# TRACE_IRQS_ON already done at io_return
 	l	%r1,BASED(.Ls390_handle_mcck)
 	basr	%r14,%r1		# TIF bit will be cleared by handler
-	b	BASED(io_work_loop)
+	TRACE_IRQS_OFF
+	b	BASED(io_return)
 
 #
 # _TIF_NEED_RESCHED is set, call schedule
 #
 io_reschedule:
-	TRACE_IRQS_ON
+	# TRACE_IRQS_ON already done at io_return
 	l	%r1,BASED(.Lschedule)
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	basr	%r14,%r1		# call scheduler
 	stnsm	__SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
 	TRACE_IRQS_OFF
-	b	BASED(io_work_loop)
+	b	BASED(io_return)
 
 #
 # _TIF_SIGPENDING is set, call do_signal
 #
 io_sigpending:
-	TRACE_IRQS_ON
+	# TRACE_IRQS_ON already done at io_return
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	l	%r1,BASED(.Ldo_signal)
 	basr	%r14,%r1		# call do_signal
 	stnsm	__SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
 	TRACE_IRQS_OFF
-	b	BASED(io_work_loop)
+	b	BASED(io_return)
 
 #
 # _TIF_SIGPENDING is set, call do_signal
 #
 io_notify_resume:
-	TRACE_IRQS_ON
+	# TRACE_IRQS_ON already done at io_return
 	stosm	__SF_EMPTY(%r15),0x03	# reenable interrupts
 	la	%r2,SP_PTREGS(%r15)	# load pt_regs
 	l	%r1,BASED(.Ldo_notify_resume)
 	basr	%r14,%r1		# call do_signal
 	stnsm	__SF_EMPTY(%r15),0xfc	# disable I/O and ext. interrupts
 	TRACE_IRQS_OFF
-	b	BASED(io_work_loop)
+	b	BASED(io_return)
 
 /*
  * External interrupt handler routine
@@ -918,14 +895,14 @@ stack_overflow:
 
 cleanup_table_system_call:
 	.long	system_call + 0x80000000, sysc_do_svc + 0x80000000
-cleanup_table_sysc_return:
-	.long	sysc_return + 0x80000000, sysc_leave + 0x80000000
-cleanup_table_sysc_leave:
-	.long	sysc_leave + 0x80000000, sysc_done + 0x80000000
-cleanup_table_io_return:
-	.long	io_return + 0x80000000, io_leave + 0x80000000
-cleanup_table_io_leave:
-	.long	io_leave + 0x80000000, io_done + 0x80000000
+cleanup_table_sysc_tif:
+	.long	sysc_tif + 0x80000000, sysc_restore + 0x80000000
+cleanup_table_sysc_restore:
+	.long	sysc_restore + 0x80000000, sysc_done + 0x80000000
+cleanup_table_io_tif:
+	.long	io_tif + 0x80000000, io_restore + 0x80000000
+cleanup_table_io_restore:
+	.long	io_restore + 0x80000000, io_done + 0x80000000
 
 cleanup_critical:
 	clc	4(4,%r12),BASED(cleanup_table_system_call)
@@ -933,25 +910,25 @@ cleanup_critical:
 	clc	4(4,%r12),BASED(cleanup_table_system_call+4)
 	bl	BASED(cleanup_system_call)
 0:
-	clc	4(4,%r12),BASED(cleanup_table_sysc_return)
+	clc	4(4,%r12),BASED(cleanup_table_sysc_tif)
 	bl	BASED(0f)
-	clc	4(4,%r12),BASED(cleanup_table_sysc_return+4)
-	bl	BASED(cleanup_sysc_return)
+	clc	4(4,%r12),BASED(cleanup_table_sysc_tif+4)
+	bl	BASED(cleanup_sysc_tif)
 0:
-	clc	4(4,%r12),BASED(cleanup_table_sysc_leave)
+	clc	4(4,%r12),BASED(cleanup_table_sysc_restore)
 	bl	BASED(0f)
-	clc	4(4,%r12),BASED(cleanup_table_sysc_leave+4)
-	bl	BASED(cleanup_sysc_leave)
+	clc	4(4,%r12),BASED(cleanup_table_sysc_restore+4)
+	bl	BASED(cleanup_sysc_restore)
 0:
-	clc	4(4,%r12),BASED(cleanup_table_io_return)
+	clc	4(4,%r12),BASED(cleanup_table_io_tif)
 	bl	BASED(0f)
-	clc	4(4,%r12),BASED(cleanup_table_io_return+4)
-	bl	BASED(cleanup_io_return)
+	clc	4(4,%r12),BASED(cleanup_table_io_tif+4)
+	bl	BASED(cleanup_io_tif)
 0:
-	clc	4(4,%r12),BASED(cleanup_table_io_leave)
+	clc	4(4,%r12),BASED(cleanup_table_io_restore)
 	bl	BASED(0f)
-	clc	4(4,%r12),BASED(cleanup_table_io_leave+4)
-	bl	BASED(cleanup_io_leave)
+	clc	4(4,%r12),BASED(cleanup_table_io_restore+4)
+	bl	BASED(cleanup_io_restore)
 0:
 	br	%r14
 
@@ -998,17 +975,17 @@ cleanup_system_call_insn:
 	.long	sysc_stime + 0x80000000
 	.long	sysc_update + 0x80000000
 
-cleanup_sysc_return:
+cleanup_sysc_tif:
 	mvc	__LC_RETURN_PSW(4),0(%r12)
-	mvc	__LC_RETURN_PSW+4(4),BASED(cleanup_table_sysc_return)
+	mvc	__LC_RETURN_PSW+4(4),BASED(cleanup_table_sysc_tif)
 	la	%r12,__LC_RETURN_PSW
 	br	%r14
 
-cleanup_sysc_leave:
-	clc	4(4,%r12),BASED(cleanup_sysc_leave_insn)
+cleanup_sysc_restore:
+	clc	4(4,%r12),BASED(cleanup_sysc_restore_insn)
 	be	BASED(2f)
 	mvc	__LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
-	clc	4(4,%r12),BASED(cleanup_sysc_leave_insn+4)
+	clc	4(4,%r12),BASED(cleanup_sysc_restore_insn+4)
 	be	BASED(2f)
 	mvc	__LC_RETURN_PSW(8),SP_PSW(%r15)
 	c	%r12,BASED(.Lmck_old_psw)
@@ -1020,21 +997,21 @@ cleanup_sysc_leave:
 	l	%r15,SP_R15(%r15)
 2:	la	%r12,__LC_RETURN_PSW
 	br	%r14
-cleanup_sysc_leave_insn:
+cleanup_sysc_restore_insn:
 	.long	sysc_done - 4 + 0x80000000
 	.long	sysc_done - 8 + 0x80000000
 
-cleanup_io_return:
+cleanup_io_tif:
 	mvc	__LC_RETURN_PSW(4),0(%r12)
-	mvc	__LC_RETURN_PSW+4(4),BASED(cleanup_table_io_return)
+	mvc	__LC_RETURN_PSW+4(4),BASED(cleanup_table_io_tif)
 	la	%r12,__LC_RETURN_PSW
 	br	%r14
 
-cleanup_io_leave:
-	clc	4(4,%r12),BASED(cleanup_io_leave_insn)
+cleanup_io_restore:
+	clc	4(4,%r12),BASED(cleanup_io_restore_insn)
 	be	BASED(2f)
 	mvc	__LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
-	clc	4(4,%r12),BASED(cleanup_io_leave_insn+4)
+	clc	4(4,%r12),BASED(cleanup_io_restore_insn+4)
 	be	BASED(2f)
 	mvc	__LC_RETURN_PSW(8),SP_PSW(%r15)
 	c	%r12,BASED(.Lmck_old_psw)
@@ -1046,7 +1023,7 @@ cleanup_io_leave:
 	l	%r15,SP_R15(%r15)
 2:	la	%r12,__LC_RETURN_PSW
 	br	%r14
-cleanup_io_leave_insn:
+cleanup_io_restore_insn:
 	.long	io_done - 4 + 0x80000000
 	.long	io_done - 8 + 0x80000000