aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/entry64.S
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2010-05-17 04:00:03 -0400
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-05-17 04:00:15 -0400
commit6377981faf1a4425b0531e577736ef03df97c8f6 (patch)
treef690c5d357413cb6f26c8463519ad2b1f8800851 /arch/s390/kernel/entry64.S
parent6a2df3a87276cdc08fd87070d09ea18d1fb9d622 (diff)
[S390] idle time accounting vs. machine checks
A machine check can interrupt the i/o and external interrupt handler anytime. If the machine check occurs while the interrupt handler is waking up from idle vtime_start_cpu can get executed a second time and the int_clock / async_enter_timer values in the lowcore get clobbered. This can confuse the cpu time accounting. To fix this problem two changes are needed. First the machine check handler has to use its own copies of int_clock and async_enter_timer, named mcck_clock and mcck_enter_timer. Second the nested execution of vtime_start_cpu has to be prevented. This is done in s390_idle_check by checking the wait bit in the program status word. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Diffstat (limited to 'arch/s390/kernel/entry64.S')
-rw-r--r--arch/s390/kernel/entry64.S54
1 files changed, 26 insertions, 28 deletions
diff --git a/arch/s390/kernel/entry64.S b/arch/s390/kernel/entry64.S
index 860cea1d1c8a..6536f5ca46f5 100644
--- a/arch/s390/kernel/entry64.S
+++ b/arch/s390/kernel/entry64.S
@@ -725,7 +725,7 @@ __critical_end:
725 */ 725 */
726 .globl mcck_int_handler 726 .globl mcck_int_handler
727mcck_int_handler: 727mcck_int_handler:
728 stck __LC_INT_CLOCK 728 stck __LC_MCCK_CLOCK
729 la %r1,4095 # revalidate r1 729 la %r1,4095 # revalidate r1
730 spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer 730 spt __LC_CPU_TIMER_SAVE_AREA-4095(%r1) # revalidate cpu timer
731 lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs 731 lmg %r0,%r15,__LC_GPREGS_SAVE_AREA-4095(%r1)# revalidate gprs
@@ -734,8 +734,7 @@ mcck_int_handler:
734 tm __LC_MCCK_CODE,0x80 # system damage? 734 tm __LC_MCCK_CODE,0x80 # system damage?
735 jo mcck_int_main # yes -> rest of mcck code invalid 735 jo mcck_int_main # yes -> rest of mcck code invalid
736 la %r14,4095 736 la %r14,4095
737 mvc __LC_SAVE_AREA+104(8),__LC_ASYNC_ENTER_TIMER 737 mvc __LC_MCCK_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14)
738 mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA-4095(%r14)
739 tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? 738 tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid?
740 jo 1f 739 jo 1f
741 la %r14,__LC_SYNC_ENTER_TIMER 740 la %r14,__LC_SYNC_ENTER_TIMER
@@ -749,7 +748,7 @@ mcck_int_handler:
749 jl 0f 748 jl 0f
750 la %r14,__LC_LAST_UPDATE_TIMER 749 la %r14,__LC_LAST_UPDATE_TIMER
7510: spt 0(%r14) 7500: spt 0(%r14)
752 mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) 751 mvc __LC_MCCK_ENTER_TIMER(8),0(%r14)
7531: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? 7521: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid?
754 jno mcck_int_main # no -> skip cleanup critical 753 jno mcck_int_main # no -> skip cleanup critical
755 tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit 754 tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit
@@ -770,9 +769,9 @@ mcck_int_main:
770 jno mcck_no_vtime # no -> no timer update 769 jno mcck_no_vtime # no -> no timer update
771 tm SP_PSW+1(%r15),0x01 # interrupting from user ? 770 tm SP_PSW+1(%r15),0x01 # interrupting from user ?
772 jz mcck_no_vtime 771 jz mcck_no_vtime
773 UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER 772 UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER
774 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER 773 UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER
775 mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER 774 mvc __LC_LAST_UPDATE_TIMER(8),__LC_MCCK_ENTER_TIMER
776mcck_no_vtime: 775mcck_no_vtime:
777 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct 776 lg %r9,__LC_THREAD_INFO # load pointer to thread_info struct
778 la %r2,SP_PTREGS(%r15) # load pt_regs 777 la %r2,SP_PTREGS(%r15) # load pt_regs
@@ -794,7 +793,6 @@ mcck_return:
794 mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW 793 mvc __LC_RETURN_MCCK_PSW(16),SP_PSW(%r15) # move return PSW
795 ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit 794 ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit
796 lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15 795 lmg %r0,%r15,SP_R0(%r15) # load gprs 0-15
797 mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+104
798 tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? 796 tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ?
799 jno 0f 797 jno 0f
800 stpt __LC_EXIT_TIMER 798 stpt __LC_EXIT_TIMER
@@ -909,15 +907,16 @@ cleanup_critical:
909 907
910cleanup_system_call: 908cleanup_system_call:
911 mvc __LC_RETURN_PSW(16),0(%r12) 909 mvc __LC_RETURN_PSW(16),0(%r12)
912 cghi %r12,__LC_MCK_OLD_PSW
913 je 0f
914 la %r12,__LC_SAVE_AREA+32
915 j 1f
9160: la %r12,__LC_SAVE_AREA+64
9171:
918 clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8) 910 clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+8)
919 jh 0f 911 jh 0f
912 mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER
913 cghi %r12,__LC_MCK_OLD_PSW
914 je 0f
920 mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER 915 mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER
9160: cghi %r12,__LC_MCK_OLD_PSW
917 la %r12,__LC_SAVE_AREA+64
918 je 0f
919 la %r12,__LC_SAVE_AREA+32
9210: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16) 9200: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16)
922 jhe cleanup_vtime 921 jhe cleanup_vtime
923 clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn) 922 clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn)
@@ -958,19 +957,22 @@ cleanup_sysc_tif:
958 957
959cleanup_sysc_restore: 958cleanup_sysc_restore:
960 clc 8(8,%r12),BASED(cleanup_sysc_restore_insn) 959 clc 8(8,%r12),BASED(cleanup_sysc_restore_insn)
961 je 3f 960 je 2f
962 clc 8(8,%r12),BASED(cleanup_sysc_restore_insn+8) 961 clc 8(8,%r12),BASED(cleanup_sysc_restore_insn+8)
963 jhe 0f 962 jhe 0f
963 mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER
964 cghi %r12,__LC_MCK_OLD_PSW
965 je 0f
964 mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER 966 mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER
9650: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) 9670: mvc __LC_RETURN_PSW(16),SP_PSW(%r15)
966 cghi %r12,__LC_MCK_OLD_PSW 968 cghi %r12,__LC_MCK_OLD_PSW
967 jne 1f 969 la %r12,__LC_SAVE_AREA+64
968 mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) 970 je 1f
969 j 2f 971 la %r12,__LC_SAVE_AREA+32
9701: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) 9721: mvc 0(32,%r12),SP_R12(%r15)
9712: lmg %r0,%r11,SP_R0(%r15) 973 lmg %r0,%r11,SP_R0(%r15)
972 lg %r15,SP_R15(%r15) 974 lg %r15,SP_R15(%r15)
9733: la %r12,__LC_RETURN_PSW 9752: la %r12,__LC_RETURN_PSW
974 br %r14 976 br %r14
975cleanup_sysc_restore_insn: 977cleanup_sysc_restore_insn:
976 .quad sysc_done - 4 978 .quad sysc_done - 4
@@ -984,19 +986,15 @@ cleanup_io_tif:
984 986
985cleanup_io_restore: 987cleanup_io_restore:
986 clc 8(8,%r12),BASED(cleanup_io_restore_insn) 988 clc 8(8,%r12),BASED(cleanup_io_restore_insn)
987 je 3f 989 je 1f
988 clc 8(8,%r12),BASED(cleanup_io_restore_insn+8) 990 clc 8(8,%r12),BASED(cleanup_io_restore_insn+8)
989 jhe 0f 991 jhe 0f
990 mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER 992 mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER
9910: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) 9930: mvc __LC_RETURN_PSW(16),SP_PSW(%r15)
992 cghi %r12,__LC_MCK_OLD_PSW
993 jne 1f
994 mvc __LC_SAVE_AREA+64(32),SP_R12(%r15) 994 mvc __LC_SAVE_AREA+64(32),SP_R12(%r15)
995 j 2f 995 lmg %r0,%r11,SP_R0(%r15)
9961: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15)
9972: lmg %r0,%r11,SP_R0(%r15)
998 lg %r15,SP_R15(%r15) 996 lg %r15,SP_R15(%r15)
9993: la %r12,__LC_RETURN_PSW 9971: la %r12,__LC_RETURN_PSW
1000 br %r14 998 br %r14
1001cleanup_io_restore_insn: 999cleanup_io_restore_insn:
1002 .quad io_done - 4 1000 .quad io_done - 4