Commit 4b7e0706620e3947dc1685dfdbc1413404afb545
Committed by
Linus Torvalds
1 parent
b2c6678c85
Exists in
master
and in
20 other branches
[PATCH] s390: idle timer setup
Fix overflow in calculation of the new tod value in stop_hz_timer and fix wrong virtual timer list idle time in case the virtual timer is already expired in stop_cpu_timer. Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 2 changed files with 22 additions and 15 deletions Side-by-side Diff
arch/s390/kernel/time.c
... | ... | @@ -244,7 +244,7 @@ |
244 | 244 | */ |
245 | 245 | static inline void stop_hz_timer(void) |
246 | 246 | { |
247 | - __u64 timer; | |
247 | + __u64 timer, todval; | |
248 | 248 | |
249 | 249 | if (sysctl_hz_timer != 0) |
250 | 250 | return; |
... | ... | @@ -265,8 +265,14 @@ |
265 | 265 | * for the next event. |
266 | 266 | */ |
267 | 267 | timer = (__u64) (next_timer_interrupt() - jiffies) + jiffies_64; |
268 | - timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY; | |
269 | - asm volatile ("SCKC %0" : : "m" (timer)); | |
268 | + todval = -1ULL; | |
269 | + /* Be careful about overflows. */ | |
270 | + if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) { | |
271 | + timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY; | |
272 | + if (timer >= jiffies_timer_cc) | |
273 | + todval = timer; | |
274 | + } | |
275 | + asm volatile ("SCKC %0" : : "m" (todval)); | |
270 | 276 | } |
271 | 277 | |
272 | 278 | /* |
arch/s390/kernel/vtime.c
... | ... | @@ -122,12 +122,17 @@ |
122 | 122 | struct vtimer_queue *vt_list; |
123 | 123 | |
124 | 124 | vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); |
125 | - set_vtimer(vt_list->idle); | |
125 | + | |
126 | + /* CPU timer interrupt is pending, don't reprogramm it */ | |
127 | + if (vt_list->idle & 1LL<<63) | |
128 | + return; | |
129 | + | |
130 | + if (!list_empty(&vt_list->list)) | |
131 | + set_vtimer(vt_list->idle); | |
126 | 132 | } |
127 | 133 | |
128 | 134 | static void stop_cpu_timer(void) |
129 | 135 | { |
130 | - __u64 done; | |
131 | 136 | struct vtimer_queue *vt_list; |
132 | 137 | |
133 | 138 | vt_list = &per_cpu(virt_cpu_timer, smp_processor_id()); |
134 | 139 | |
135 | 140 | |
136 | 141 | |
137 | 142 | |
... | ... | @@ -138,21 +143,17 @@ |
138 | 143 | goto fire; |
139 | 144 | } |
140 | 145 | |
141 | - /* store progress */ | |
142 | - asm volatile ("STPT %0" : "=m" (done)); | |
146 | + /* store the actual expire value */ | |
147 | + asm volatile ("STPT %0" : "=m" (vt_list->idle)); | |
143 | 148 | |
144 | 149 | /* |
145 | - * If done is negative we do not stop the CPU timer | |
146 | - * because we will get instantly an interrupt that | |
147 | - * will start the CPU timer again. | |
150 | + * If the CPU timer is negative we don't reprogramm | |
151 | + * it because we will get instantly an interrupt. | |
148 | 152 | */ |
149 | - if (done & 1LL<<63) | |
153 | + if (vt_list->idle & 1LL<<63) | |
150 | 154 | return; |
151 | - else | |
152 | - vt_list->offset += vt_list->to_expire - done; | |
153 | 155 | |
154 | - /* save the actual expire value */ | |
155 | - vt_list->idle = done; | |
156 | + vt_list->offset += vt_list->to_expire - vt_list->idle; | |
156 | 157 | |
157 | 158 | /* |
158 | 159 | * We cannot halt the CPU timer, we just write a value that |