aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/include
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/include
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/include')
-rw-r--r--arch/s390/include/asm/cputime.h9
-rw-r--r--arch/s390/include/asm/lowcore.h98
2 files changed, 56 insertions, 51 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 */