aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
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
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')
-rw-r--r--arch/s390/include/asm/cputime.h9
-rw-r--r--arch/s390/include/asm/lowcore.h98
-rw-r--r--arch/s390/kernel/asm-offsets.c2
-rw-r--r--arch/s390/kernel/entry.S54
-rw-r--r--arch/s390/kernel/entry64.S54
-rw-r--r--arch/s390/kernel/nmi.c3
-rw-r--r--arch/s390/kernel/s390_ext.c3
-rw-r--r--arch/s390/kernel/vtime.c15
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
189DECLARE_PER_CPU(struct s390_idle_data, s390_idle); 189DECLARE_PER_CPU(struct s390_idle_data, s390_idle);
190 190
191void vtime_start_cpu(void); 191void vtime_start_cpu(__u64 int_clock, __u64 enter_timer);
192cputime64_t s390_get_idle_time(int cpu); 192cputime64_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
196static inline void s390_idle_check(void) 196static 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
202static inline int s390_nohz_delay(int cpu) 203static 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
744mcck_int_handler: 744mcck_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
7660: spt 0(%r14) 7650: spt 0(%r14)
767 mvc __LC_ASYNC_ENTER_TIMER(8),0(%r14) 766 mvc __LC_MCCK_ENTER_TIMER(8),0(%r14)
7681: tm __LC_MCCK_CODE+2,0x09 # mwp + ia of old psw valid? 7671: 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
792mcck_no_vtime: 791mcck_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:
811mcck_return: 810mcck_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
935cleanup_system_call: 933cleanup_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)
9410: la %r12,__LC_SAVE_AREA+32
9421:
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
9410: c %r12,BASED(.Lmck_old_psw)
942 la %r12,__LC_SAVE_AREA+32
943 be BASED(0f)
944 la %r12,__LC_SAVE_AREA+16
9460: clc __LC_RETURN_PSW+4(4),BASED(cleanup_system_call_insn+8) 9450: 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:
984cleanup_sysc_restore: 983cleanup_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) 9900: 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
9950: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15) 9971: mvc 0(16,%r12),SP_R12(%r15)
9961: 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)
9982: la %r12,__LC_RETURN_PSW 10002: la %r12,__LC_RETURN_PSW
999 br %r14 1001 br %r14
@@ -1009,19 +1011,15 @@ cleanup_io_tif:
1009 1011
1010cleanup_io_restore: 1012cleanup_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)
10210: mvc __LC_SAVE_AREA+16(16),SP_R12(%r15)
10221: lm %r0,%r11,SP_R0(%r15)
1023 l %r15,SP_R15(%r15) 1021 l %r15,SP_R15(%r15)
10242: la %r12,__LC_RETURN_PSW 10221: la %r12,__LC_RETURN_PSW
1025 br %r14 1023 br %r14
1026cleanup_io_restore_insn: 1024cleanup_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
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
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}
122EXPORT_SYMBOL_GPL(account_system_vtime); 122EXPORT_SYMBOL_GPL(account_system_vtime);
123 123
124void vtime_start_cpu(void) 124void 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++;