diff options
author | Martin Schwidefsky <schwidefsky@de.ibm.com> | 2010-05-17 04:00:03 -0400 |
---|---|---|
committer | Martin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com> | 2010-05-17 04:00:15 -0400 |
commit | 6377981faf1a4425b0531e577736ef03df97c8f6 (patch) | |
tree | f690c5d357413cb6f26c8463519ad2b1f8800851 /arch/s390/kernel/entry64.S | |
parent | 6a2df3a87276cdc08fd87070d09ea18d1fb9d622 (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.S | 54 |
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 |
727 | mcck_int_handler: | 727 | mcck_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 |
751 | 0: spt 0(%r14) | 750 | 0: spt 0(%r14) |
752 | mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) | 751 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
753 | 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 752 | 1: 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 |
776 | mcck_no_vtime: | 775 | mcck_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 | ||
910 | cleanup_system_call: | 908 | cleanup_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 | ||
916 | 0: la %r12,__LC_SAVE_AREA+64 | ||
917 | 1: | ||
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 |
916 | 0: cghi %r12,__LC_MCK_OLD_PSW | ||
917 | la %r12,__LC_SAVE_AREA+64 | ||
918 | je 0f | ||
919 | la %r12,__LC_SAVE_AREA+32 | ||
921 | 0: clc __LC_RETURN_PSW+8(8),BASED(cleanup_system_call_insn+16) | 920 | 0: 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 | ||
959 | cleanup_sysc_restore: | 958 | cleanup_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 |
965 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | 967 | 0: 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 |
970 | 1: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) | 972 | 1: mvc 0(32,%r12),SP_R12(%r15) |
971 | 2: 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) |
973 | 3: la %r12,__LC_RETURN_PSW | 975 | 2: la %r12,__LC_RETURN_PSW |
974 | br %r14 | 976 | br %r14 |
975 | cleanup_sysc_restore_insn: | 977 | cleanup_sysc_restore_insn: |
976 | .quad sysc_done - 4 | 978 | .quad sysc_done - 4 |
@@ -984,19 +986,15 @@ cleanup_io_tif: | |||
984 | 986 | ||
985 | cleanup_io_restore: | 987 | cleanup_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 |
991 | 0: mvc __LC_RETURN_PSW(16),SP_PSW(%r15) | 993 | 0: 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) |
996 | 1: mvc __LC_SAVE_AREA+32(32),SP_R12(%r15) | ||
997 | 2: lmg %r0,%r11,SP_R0(%r15) | ||
998 | lg %r15,SP_R15(%r15) | 996 | lg %r15,SP_R15(%r15) |
999 | 3: la %r12,__LC_RETURN_PSW | 997 | 1: la %r12,__LC_RETURN_PSW |
1000 | br %r14 | 998 | br %r14 |
1001 | cleanup_io_restore_insn: | 999 | cleanup_io_restore_insn: |
1002 | .quad io_done - 4 | 1000 | .quad io_done - 4 |