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 | |
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')
-rw-r--r-- | arch/s390/include/asm/cputime.h | 9 | ||||
-rw-r--r-- | arch/s390/include/asm/lowcore.h | 98 | ||||
-rw-r--r-- | arch/s390/kernel/asm-offsets.c | 2 | ||||
-rw-r--r-- | arch/s390/kernel/entry.S | 54 | ||||
-rw-r--r-- | arch/s390/kernel/entry64.S | 54 | ||||
-rw-r--r-- | arch/s390/kernel/nmi.c | 3 | ||||
-rw-r--r-- | arch/s390/kernel/s390_ext.c | 3 | ||||
-rw-r--r-- | arch/s390/kernel/vtime.c | 15 |
8 files changed, 123 insertions, 115 deletions
diff --git a/arch/s390/include/asm/cputime.h b/arch/s390/include/asm/cputime.h index 258ba88b7b50..8b1a52a137c5 100644 --- a/arch/s390/include/asm/cputime.h +++ b/arch/s390/include/asm/cputime.h | |||
@@ -188,15 +188,16 @@ struct s390_idle_data { | |||
188 | 188 | ||
189 | DECLARE_PER_CPU(struct s390_idle_data, s390_idle); | 189 | DECLARE_PER_CPU(struct s390_idle_data, s390_idle); |
190 | 190 | ||
191 | void vtime_start_cpu(void); | 191 | void vtime_start_cpu(__u64 int_clock, __u64 enter_timer); |
192 | cputime64_t s390_get_idle_time(int cpu); | 192 | cputime64_t s390_get_idle_time(int cpu); |
193 | 193 | ||
194 | #define arch_idle_time(cpu) s390_get_idle_time(cpu) | 194 | #define arch_idle_time(cpu) s390_get_idle_time(cpu) |
195 | 195 | ||
196 | static inline void s390_idle_check(void) | 196 | static inline void s390_idle_check(struct pt_regs *regs, __u64 int_clock, |
197 | __u64 enter_timer) | ||
197 | { | 198 | { |
198 | if ((&__get_cpu_var(s390_idle))->idle_enter != 0ULL) | 199 | if (regs->psw.mask & PSW_MASK_WAIT) |
199 | vtime_start_cpu(); | 200 | vtime_start_cpu(int_clock, enter_timer); |
200 | } | 201 | } |
201 | 202 | ||
202 | static inline int s390_nohz_delay(int cpu) | 203 | static inline int s390_nohz_delay(int cpu) |
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h index f7e78c79b8b1..2c02d46c3588 100644 --- a/arch/s390/include/asm/lowcore.h +++ b/arch/s390/include/asm/lowcore.h | |||
@@ -104,37 +104,39 @@ struct _lowcore { | |||
104 | /* CPU time accounting values */ | 104 | /* CPU time accounting values */ |
105 | __u64 sync_enter_timer; /* 0x0250 */ | 105 | __u64 sync_enter_timer; /* 0x0250 */ |
106 | __u64 async_enter_timer; /* 0x0258 */ | 106 | __u64 async_enter_timer; /* 0x0258 */ |
107 | __u64 exit_timer; /* 0x0260 */ | 107 | __u64 mcck_enter_timer; /* 0x0260 */ |
108 | __u64 user_timer; /* 0x0268 */ | 108 | __u64 exit_timer; /* 0x0268 */ |
109 | __u64 system_timer; /* 0x0270 */ | 109 | __u64 user_timer; /* 0x0270 */ |
110 | __u64 steal_timer; /* 0x0278 */ | 110 | __u64 system_timer; /* 0x0278 */ |
111 | __u64 last_update_timer; /* 0x0280 */ | 111 | __u64 steal_timer; /* 0x0280 */ |
112 | __u64 last_update_clock; /* 0x0288 */ | 112 | __u64 last_update_timer; /* 0x0288 */ |
113 | __u64 last_update_clock; /* 0x0290 */ | ||
113 | 114 | ||
114 | /* Current process. */ | 115 | /* Current process. */ |
115 | __u32 current_task; /* 0x0290 */ | 116 | __u32 current_task; /* 0x0298 */ |
116 | __u32 thread_info; /* 0x0294 */ | 117 | __u32 thread_info; /* 0x029c */ |
117 | __u32 kernel_stack; /* 0x0298 */ | 118 | __u32 kernel_stack; /* 0x02a0 */ |
118 | 119 | ||
119 | /* Interrupt and panic stack. */ | 120 | /* Interrupt and panic stack. */ |
120 | __u32 async_stack; /* 0x029c */ | 121 | __u32 async_stack; /* 0x02a4 */ |
121 | __u32 panic_stack; /* 0x02a0 */ | 122 | __u32 panic_stack; /* 0x02a8 */ |
122 | 123 | ||
123 | /* Address space pointer. */ | 124 | /* Address space pointer. */ |
124 | __u32 kernel_asce; /* 0x02a4 */ | 125 | __u32 kernel_asce; /* 0x02ac */ |
125 | __u32 user_asce; /* 0x02a8 */ | 126 | __u32 user_asce; /* 0x02b0 */ |
126 | __u32 user_exec_asce; /* 0x02ac */ | 127 | __u32 user_exec_asce; /* 0x02b4 */ |
127 | 128 | ||
128 | /* SMP info area */ | 129 | /* SMP info area */ |
129 | __u32 cpu_nr; /* 0x02b0 */ | 130 | __u32 cpu_nr; /* 0x02b8 */ |
130 | __u32 softirq_pending; /* 0x02b4 */ | 131 | __u32 softirq_pending; /* 0x02bc */ |
131 | __u32 percpu_offset; /* 0x02b8 */ | 132 | __u32 percpu_offset; /* 0x02c0 */ |
132 | __u32 ext_call_fast; /* 0x02bc */ | 133 | __u32 ext_call_fast; /* 0x02c4 */ |
133 | __u64 int_clock; /* 0x02c0 */ | 134 | __u64 int_clock; /* 0x02c8 */ |
134 | __u64 clock_comparator; /* 0x02c8 */ | 135 | __u64 mcck_clock; /* 0x02d0 */ |
135 | __u32 machine_flags; /* 0x02d0 */ | 136 | __u64 clock_comparator; /* 0x02d8 */ |
136 | __u32 ftrace_func; /* 0x02d4 */ | 137 | __u32 machine_flags; /* 0x02e0 */ |
137 | __u8 pad_0x02d8[0x0300-0x02d8]; /* 0x02d8 */ | 138 | __u32 ftrace_func; /* 0x02e4 */ |
139 | __u8 pad_0x02e8[0x0300-0x02e8]; /* 0x02e8 */ | ||
138 | 140 | ||
139 | /* Interrupt response block */ | 141 | /* Interrupt response block */ |
140 | __u8 irb[64]; /* 0x0300 */ | 142 | __u8 irb[64]; /* 0x0300 */ |
@@ -232,38 +234,40 @@ struct _lowcore { | |||
232 | /* CPU accounting and timing values. */ | 234 | /* CPU accounting and timing values. */ |
233 | __u64 sync_enter_timer; /* 0x02a0 */ | 235 | __u64 sync_enter_timer; /* 0x02a0 */ |
234 | __u64 async_enter_timer; /* 0x02a8 */ | 236 | __u64 async_enter_timer; /* 0x02a8 */ |
235 | __u64 exit_timer; /* 0x02b0 */ | 237 | __u64 mcck_enter_timer; /* 0x02b0 */ |
236 | __u64 user_timer; /* 0x02b8 */ | 238 | __u64 exit_timer; /* 0x02b8 */ |
237 | __u64 system_timer; /* 0x02c0 */ | 239 | __u64 user_timer; /* 0x02c0 */ |
238 | __u64 steal_timer; /* 0x02c8 */ | 240 | __u64 system_timer; /* 0x02c8 */ |
239 | __u64 last_update_timer; /* 0x02d0 */ | 241 | __u64 steal_timer; /* 0x02d0 */ |
240 | __u64 last_update_clock; /* 0x02d8 */ | 242 | __u64 last_update_timer; /* 0x02d8 */ |
243 | __u64 last_update_clock; /* 0x02e0 */ | ||
241 | 244 | ||
242 | /* Current process. */ | 245 | /* Current process. */ |
243 | __u64 current_task; /* 0x02e0 */ | 246 | __u64 current_task; /* 0x02e8 */ |
244 | __u64 thread_info; /* 0x02e8 */ | 247 | __u64 thread_info; /* 0x02f0 */ |
245 | __u64 kernel_stack; /* 0x02f0 */ | 248 | __u64 kernel_stack; /* 0x02f8 */ |
246 | 249 | ||
247 | /* Interrupt and panic stack. */ | 250 | /* Interrupt and panic stack. */ |
248 | __u64 async_stack; /* 0x02f8 */ | 251 | __u64 async_stack; /* 0x0300 */ |
249 | __u64 panic_stack; /* 0x0300 */ | 252 | __u64 panic_stack; /* 0x0308 */ |
250 | 253 | ||
251 | /* Address space pointer. */ | 254 | /* Address space pointer. */ |
252 | __u64 kernel_asce; /* 0x0308 */ | 255 | __u64 kernel_asce; /* 0x0310 */ |
253 | __u64 user_asce; /* 0x0310 */ | 256 | __u64 user_asce; /* 0x0318 */ |
254 | __u64 user_exec_asce; /* 0x0318 */ | 257 | __u64 user_exec_asce; /* 0x0320 */ |
255 | 258 | ||
256 | /* SMP info area */ | 259 | /* SMP info area */ |
257 | __u32 cpu_nr; /* 0x0320 */ | 260 | __u32 cpu_nr; /* 0x0328 */ |
258 | __u32 softirq_pending; /* 0x0324 */ | 261 | __u32 softirq_pending; /* 0x032c */ |
259 | __u64 percpu_offset; /* 0x0328 */ | 262 | __u64 percpu_offset; /* 0x0330 */ |
260 | __u64 ext_call_fast; /* 0x0330 */ | 263 | __u64 ext_call_fast; /* 0x0338 */ |
261 | __u64 int_clock; /* 0x0338 */ | 264 | __u64 int_clock; /* 0x0340 */ |
262 | __u64 clock_comparator; /* 0x0340 */ | 265 | __u64 mcck_clock; /* 0x0348 */ |
263 | __u64 vdso_per_cpu_data; /* 0x0348 */ | 266 | __u64 clock_comparator; /* 0x0350 */ |
264 | __u64 machine_flags; /* 0x0350 */ | 267 | __u64 vdso_per_cpu_data; /* 0x0358 */ |
265 | __u64 ftrace_func; /* 0x0358 */ | 268 | __u64 machine_flags; /* 0x0360 */ |
266 | __u8 pad_0x0368[0x0380-0x0360]; /* 0x0360 */ | 269 | __u64 ftrace_func; /* 0x0368 */ |
270 | __u8 pad_0x0370[0x0380-0x0370]; /* 0x0370 */ | ||
267 | 271 | ||
268 | /* Interrupt response block. */ | 272 | /* Interrupt response block. */ |
269 | __u8 irb[64]; /* 0x0380 */ | 273 | __u8 irb[64]; /* 0x0380 */ |
diff --git a/arch/s390/kernel/asm-offsets.c b/arch/s390/kernel/asm-offsets.c index 32b1ede69858..816d81f479c0 100644 --- a/arch/s390/kernel/asm-offsets.c +++ b/arch/s390/kernel/asm-offsets.c | |||
@@ -112,6 +112,7 @@ int main(void) | |||
112 | DEFINE(__LC_RETURN_MCCK_PSW, offsetof(struct _lowcore, return_mcck_psw)); | 112 | DEFINE(__LC_RETURN_MCCK_PSW, offsetof(struct _lowcore, return_mcck_psw)); |
113 | DEFINE(__LC_SYNC_ENTER_TIMER, offsetof(struct _lowcore, sync_enter_timer)); | 113 | DEFINE(__LC_SYNC_ENTER_TIMER, offsetof(struct _lowcore, sync_enter_timer)); |
114 | DEFINE(__LC_ASYNC_ENTER_TIMER, offsetof(struct _lowcore, async_enter_timer)); | 114 | DEFINE(__LC_ASYNC_ENTER_TIMER, offsetof(struct _lowcore, async_enter_timer)); |
115 | DEFINE(__LC_MCCK_ENTER_TIMER, offsetof(struct _lowcore, mcck_enter_timer)); | ||
115 | DEFINE(__LC_EXIT_TIMER, offsetof(struct _lowcore, exit_timer)); | 116 | DEFINE(__LC_EXIT_TIMER, offsetof(struct _lowcore, exit_timer)); |
116 | DEFINE(__LC_USER_TIMER, offsetof(struct _lowcore, user_timer)); | 117 | DEFINE(__LC_USER_TIMER, offsetof(struct _lowcore, user_timer)); |
117 | DEFINE(__LC_SYSTEM_TIMER, offsetof(struct _lowcore, system_timer)); | 118 | DEFINE(__LC_SYSTEM_TIMER, offsetof(struct _lowcore, system_timer)); |
@@ -127,6 +128,7 @@ int main(void) | |||
127 | DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); | 128 | DEFINE(__LC_USER_ASCE, offsetof(struct _lowcore, user_asce)); |
128 | DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce)); | 129 | DEFINE(__LC_USER_EXEC_ASCE, offsetof(struct _lowcore, user_exec_asce)); |
129 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); | 130 | DEFINE(__LC_INT_CLOCK, offsetof(struct _lowcore, int_clock)); |
131 | DEFINE(__LC_MCCK_CLOCK, offsetof(struct _lowcore, mcck_clock)); | ||
130 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); | 132 | DEFINE(__LC_MACHINE_FLAGS, offsetof(struct _lowcore, machine_flags)); |
131 | DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); | 133 | DEFINE(__LC_FTRACE_FUNC, offsetof(struct _lowcore, ftrace_func)); |
132 | DEFINE(__LC_IRB, offsetof(struct _lowcore, irb)); | 134 | DEFINE(__LC_IRB, offsetof(struct _lowcore, irb)); |
diff --git a/arch/s390/kernel/entry.S b/arch/s390/kernel/entry.S index 07d849995dac..0e2b16241dfa 100644 --- a/arch/s390/kernel/entry.S +++ b/arch/s390/kernel/entry.S | |||
@@ -742,15 +742,14 @@ __critical_end: | |||
742 | 742 | ||
743 | .globl mcck_int_handler | 743 | .globl mcck_int_handler |
744 | mcck_int_handler: | 744 | mcck_int_handler: |
745 | stck __LC_INT_CLOCK | 745 | stck __LC_MCCK_CLOCK |
746 | spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer | 746 | spt __LC_CPU_TIMER_SAVE_AREA # revalidate cpu timer |
747 | lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs | 747 | lm %r0,%r15,__LC_GPREGS_SAVE_AREA # revalidate gprs |
748 | SAVE_ALL_BASE __LC_SAVE_AREA+32 | 748 | SAVE_ALL_BASE __LC_SAVE_AREA+32 |
749 | la %r12,__LC_MCK_OLD_PSW | 749 | la %r12,__LC_MCK_OLD_PSW |
750 | tm __LC_MCCK_CODE,0x80 # system damage? | 750 | tm __LC_MCCK_CODE,0x80 # system damage? |
751 | bo BASED(mcck_int_main) # yes -> rest of mcck code invalid | 751 | bo BASED(mcck_int_main) # yes -> rest of mcck code invalid |
752 | mvc __LC_SAVE_AREA+52(8),__LC_ASYNC_ENTER_TIMER | 752 | mvc __LC_MCCK_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA |
753 | mvc __LC_ASYNC_ENTER_TIMER(8),__LC_CPU_TIMER_SAVE_AREA | ||
754 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? | 753 | tm __LC_MCCK_CODE+5,0x02 # stored cpu timer value valid? |
755 | bo BASED(1f) | 754 | bo BASED(1f) |
756 | la %r14,__LC_SYNC_ENTER_TIMER | 755 | la %r14,__LC_SYNC_ENTER_TIMER |
@@ -764,7 +763,7 @@ mcck_int_handler: | |||
764 | bl BASED(0f) | 763 | bl BASED(0f) |
765 | la %r14,__LC_LAST_UPDATE_TIMER | 764 | la %r14,__LC_LAST_UPDATE_TIMER |
766 | 0: spt 0(%r14) | 765 | 0: spt 0(%r14) |
767 | mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) | 766 | mvc __LC_MCCK_ENTER_TIMER(8),0(%r14) |
768 | 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? | 767 | 1: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? |
769 | bno BASED(mcck_int_main) # no -> skip cleanup critical | 768 | bno BASED(mcck_int_main) # no -> skip cleanup critical |
770 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit | 769 | tm __LC_MCK_OLD_PSW+1,0x01 # test problem state bit |
@@ -786,9 +785,9 @@ mcck_int_main: | |||
786 | bno BASED(mcck_no_vtime) # no -> skip cleanup critical | 785 | bno BASED(mcck_no_vtime) # no -> skip cleanup critical |
787 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? | 786 | tm SP_PSW+1(%r15),0x01 # interrupting from user ? |
788 | bz BASED(mcck_no_vtime) | 787 | bz BASED(mcck_no_vtime) |
789 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_ASYNC_ENTER_TIMER,__LC_USER_TIMER | 788 | UPDATE_VTIME __LC_EXIT_TIMER,__LC_MCCK_ENTER_TIMER,__LC_USER_TIMER |
790 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER | 789 | UPDATE_VTIME __LC_LAST_UPDATE_TIMER,__LC_EXIT_TIMER,__LC_SYSTEM_TIMER |
791 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_ASYNC_ENTER_TIMER | 790 | mvc __LC_LAST_UPDATE_TIMER(8),__LC_MCCK_ENTER_TIMER |
792 | mcck_no_vtime: | 791 | mcck_no_vtime: |
793 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct | 792 | l %r9,__LC_THREAD_INFO # load pointer to thread_info struct |
794 | la %r2,SP_PTREGS(%r15) # load pt_regs | 793 | la %r2,SP_PTREGS(%r15) # load pt_regs |
@@ -811,7 +810,6 @@ mcck_no_vtime: | |||
811 | mcck_return: | 810 | mcck_return: |
812 | mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW | 811 | mvc __LC_RETURN_MCCK_PSW(8),SP_PSW(%r15) # move return PSW |
813 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit | 812 | ni __LC_RETURN_MCCK_PSW+1,0xfd # clear wait state bit |
814 | mvc __LC_ASYNC_ENTER_TIMER(8),__LC_SAVE_AREA+52 | ||
815 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? | 813 | tm __LC_RETURN_MCCK_PSW+1,0x01 # returning to user ? |
816 | bno BASED(0f) | 814 | bno BASED(0f) |
817 | lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 | 815 | lm %r0,%r15,SP_R0(%r15) # load gprs 0-15 |
@@ -934,15 +932,16 @@ cleanup_critical: | |||
934 | 932 | ||
935 | cleanup_system_call: | 933 | cleanup_system_call: |
936 | mvc __LC_RETURN_PSW(8),0(%r12) | 934 | mvc __LC_RETURN_PSW(8),0(%r12) |
937 | c %r12,BASED(.Lmck_old_psw) | ||
938 | be BASED(0f) | ||
939 | la %r12,__LC_SAVE_AREA+16 | ||
940 | b BASED(1f) | ||
941 | 0: la %r12,__LC_SAVE_AREA+32 | ||
942 | 1: | ||
943 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4) | 935 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+4) |
944 | bh BASED(0f) | 936 | bh BASED(0f) |
937 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
938 | c %r12,BASED(.Lmck_old_psw) | ||
939 | be BASED(0f) | ||
945 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER | 940 | mvc __LC_SYNC_ENTER_TIMER(8),__LC_ASYNC_ENTER_TIMER |
941 | 0: c %r12,BASED(.Lmck_old_psw) | ||
942 | la %r12,__LC_SAVE_AREA+32 | ||
943 | be BASED(0f) | ||
944 | la %r12,__LC_SAVE_AREA+16 | ||
946 | 0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) | 945 | 0: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) |
947 | bhe BASED(cleanup_vtime) | 946 | bhe BASED(cleanup_vtime) |
948 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn) | 947 | clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn) |
@@ -984,16 +983,19 @@ cleanup_sysc_tif: | |||
984 | cleanup_sysc_restore: | 983 | cleanup_sysc_restore: |
985 | clc 4(4,%r12),BASED(cleanup_sysc_restore_insn) | 984 | clc 4(4,%r12),BASED(cleanup_sysc_restore_insn) |
986 | be BASED(2f) | 985 | be BASED(2f) |
986 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER | ||
987 | c %r12,BASED(.Lmck_old_psw) | ||
988 | be BASED(0f) | ||
987 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | 989 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER |
988 | clc 4(4,%r12),BASED(cleanup_sysc_restore_insn+4) | 990 | 0: clc 4(4,%r12),BASED(cleanup_sysc_restore_insn+4) |
989 | be BASED(2f) | 991 | be BASED(2f) |
990 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) | 992 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) |
991 | c %r12,BASED(.Lmck_old_psw) | 993 | c %r12,BASED(.Lmck_old_psw) |
992 | bne BASED(0f) | 994 | la %r12,__LC_SAVE_AREA+32 |
993 | mvc __LC_SAVE_AREA+32(16),SP_R12(%r15) | 995 | be BASED(1f) |
994 | b BASED(1f) | 996 | la %r12,__LC_SAVE_AREA+16 |
995 | 0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15) | 997 | 1: mvc 0(16,%r12),SP_R12(%r15) |
996 | 1: lm %r0,%r11,SP_R0(%r15) | 998 | lm %r0,%r11,SP_R0(%r15) |
997 | l %r15,SP_R15(%r15) | 999 | l %r15,SP_R15(%r15) |
998 | 2: la %r12,__LC_RETURN_PSW | 1000 | 2: la %r12,__LC_RETURN_PSW |
999 | br %r14 | 1001 | br %r14 |
@@ -1009,19 +1011,15 @@ cleanup_io_tif: | |||
1009 | 1011 | ||
1010 | cleanup_io_restore: | 1012 | cleanup_io_restore: |
1011 | clc 4(4,%r12),BASED(cleanup_io_restore_insn) | 1013 | clc 4(4,%r12),BASED(cleanup_io_restore_insn) |
1012 | be BASED(2f) | 1014 | be BASED(1f) |
1013 | mvc __LC_EXIT_TIMER(8),__LC_ASYNC_ENTER_TIMER | 1015 | mvc __LC_EXIT_TIMER(8),__LC_MCCK_ENTER_TIMER |
1014 | clc 4(4,%r12),BASED(cleanup_io_restore_insn+4) | 1016 | clc 4(4,%r12),BASED(cleanup_io_restore_insn+4) |
1015 | be BASED(2f) | 1017 | be BASED(1f) |
1016 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) | 1018 | mvc __LC_RETURN_PSW(8),SP_PSW(%r15) |
1017 | c %r12,BASED(.Lmck_old_psw) | ||
1018 | bne BASED(0f) | ||
1019 | mvc __LC_SAVE_AREA+32(16),SP_R12(%r15) | 1019 | mvc __LC_SAVE_AREA+32(16),SP_R12(%r15) |
1020 | b BASED(1f) | 1020 | lm %r0,%r11,SP_R0(%r15) |
1021 | 0: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15) | ||
1022 | 1: lm %r0,%r11,SP_R0(%r15) | ||
1023 | l %r15,SP_R15(%r15) | 1021 | l %r15,SP_R15(%r15) |
1024 | 2: la %r12,__LC_RETURN_PSW | 1022 | 1: la %r12,__LC_RETURN_PSW |
1025 | br %r14 | 1023 | br %r14 |
1026 | cleanup_io_restore_insn: | 1024 | cleanup_io_restore_insn: |
1027 | .long io_done - 4 + 0x80000000 | 1025 | .long io_done - 4 + 0x80000000 |
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 |
diff --git a/arch/s390/kernel/nmi.c b/arch/s390/kernel/nmi.c index 015e27da40eb..ac151399ef34 100644 --- a/arch/s390/kernel/nmi.c +++ b/arch/s390/kernel/nmi.c | |||
@@ -255,7 +255,8 @@ void notrace s390_do_machine_check(struct pt_regs *regs) | |||
255 | int umode; | 255 | int umode; |
256 | 256 | ||
257 | nmi_enter(); | 257 | nmi_enter(); |
258 | s390_idle_check(); | 258 | s390_idle_check(regs, S390_lowcore.mcck_clock, |
259 | S390_lowcore.mcck_enter_timer); | ||
259 | 260 | ||
260 | mci = (struct mci *) &S390_lowcore.mcck_interruption_code; | 261 | mci = (struct mci *) &S390_lowcore.mcck_interruption_code; |
261 | mcck = &__get_cpu_var(cpu_mcck); | 262 | mcck = &__get_cpu_var(cpu_mcck); |
diff --git a/arch/s390/kernel/s390_ext.c b/arch/s390/kernel/s390_ext.c index 59618bcd99b7..9ce641b5291f 100644 --- a/arch/s390/kernel/s390_ext.c +++ b/arch/s390/kernel/s390_ext.c | |||
@@ -120,7 +120,8 @@ void __irq_entry do_extint(struct pt_regs *regs, unsigned short code) | |||
120 | struct pt_regs *old_regs; | 120 | struct pt_regs *old_regs; |
121 | 121 | ||
122 | old_regs = set_irq_regs(regs); | 122 | old_regs = set_irq_regs(regs); |
123 | s390_idle_check(); | 123 | s390_idle_check(regs, S390_lowcore.int_clock, |
124 | S390_lowcore.async_enter_timer); | ||
124 | irq_enter(); | 125 | irq_enter(); |
125 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) | 126 | if (S390_lowcore.int_clock >= S390_lowcore.clock_comparator) |
126 | /* Serve timer interrupts first. */ | 127 | /* Serve timer interrupts first. */ |
diff --git a/arch/s390/kernel/vtime.c b/arch/s390/kernel/vtime.c index b59a812a010e..3479f1b0d4e0 100644 --- a/arch/s390/kernel/vtime.c +++ b/arch/s390/kernel/vtime.c | |||
@@ -121,32 +121,35 @@ void account_system_vtime(struct task_struct *tsk) | |||
121 | } | 121 | } |
122 | EXPORT_SYMBOL_GPL(account_system_vtime); | 122 | EXPORT_SYMBOL_GPL(account_system_vtime); |
123 | 123 | ||
124 | void vtime_start_cpu(void) | 124 | void vtime_start_cpu(__u64 int_clock, __u64 enter_timer) |
125 | { | 125 | { |
126 | struct s390_idle_data *idle = &__get_cpu_var(s390_idle); | 126 | struct s390_idle_data *idle = &__get_cpu_var(s390_idle); |
127 | struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer); | 127 | struct vtimer_queue *vq = &__get_cpu_var(virt_cpu_timer); |
128 | __u64 idle_time, expires; | 128 | __u64 idle_time, expires; |
129 | 129 | ||
130 | if (idle->idle_enter == 0ULL) | ||
131 | return; | ||
132 | |||
130 | /* Account time spent with enabled wait psw loaded as idle time. */ | 133 | /* Account time spent with enabled wait psw loaded as idle time. */ |
131 | idle_time = S390_lowcore.int_clock - idle->idle_enter; | 134 | idle_time = int_clock - idle->idle_enter; |
132 | account_idle_time(idle_time); | 135 | account_idle_time(idle_time); |
133 | S390_lowcore.steal_timer += | 136 | S390_lowcore.steal_timer += |
134 | idle->idle_enter - S390_lowcore.last_update_clock; | 137 | idle->idle_enter - S390_lowcore.last_update_clock; |
135 | S390_lowcore.last_update_clock = S390_lowcore.int_clock; | 138 | S390_lowcore.last_update_clock = int_clock; |
136 | 139 | ||
137 | /* Account system time spent going idle. */ | 140 | /* Account system time spent going idle. */ |
138 | S390_lowcore.system_timer += S390_lowcore.last_update_timer - vq->idle; | 141 | S390_lowcore.system_timer += S390_lowcore.last_update_timer - vq->idle; |
139 | S390_lowcore.last_update_timer = S390_lowcore.async_enter_timer; | 142 | S390_lowcore.last_update_timer = enter_timer; |
140 | 143 | ||
141 | /* Restart vtime CPU timer */ | 144 | /* Restart vtime CPU timer */ |
142 | if (vq->do_spt) { | 145 | if (vq->do_spt) { |
143 | /* Program old expire value but first save progress. */ | 146 | /* Program old expire value but first save progress. */ |
144 | expires = vq->idle - S390_lowcore.async_enter_timer; | 147 | expires = vq->idle - enter_timer; |
145 | expires += get_vtimer(); | 148 | expires += get_vtimer(); |
146 | set_vtimer(expires); | 149 | set_vtimer(expires); |
147 | } else { | 150 | } else { |
148 | /* Don't account the CPU timer delta while the cpu was idle. */ | 151 | /* Don't account the CPU timer delta while the cpu was idle. */ |
149 | vq->elapsed -= vq->idle - S390_lowcore.async_enter_timer; | 152 | vq->elapsed -= vq->idle - enter_timer; |
150 | } | 153 | } |
151 | 154 | ||
152 | idle->sequence++; | 155 | idle->sequence++; |