blob: 1254a4d0d7622d051a3d2b58762dadf4fb86922e [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * arch/s390/kernel/vtime.c
3 * Virtual cpu timer based timer functions.
4 *
5 * S390 version
6 * Copyright (C) 2004 IBM Deutschland Entwicklung GmbH, IBM Corporation
7 * Author(s): Jan Glauber <jan.glauber@de.ibm.com>
8 */
9
Linus Torvalds1da177e2005-04-16 15:20:36 -070010#include <linux/module.h>
11#include <linux/kernel.h>
12#include <linux/time.h>
13#include <linux/delay.h>
14#include <linux/init.h>
15#include <linux/smp.h>
16#include <linux/types.h>
17#include <linux/timex.h>
18#include <linux/notifier.h>
19#include <linux/kernel_stat.h>
20#include <linux/rcupdate.h>
21#include <linux/posix-timers.h>
22
23#include <asm/s390_ext.h>
24#include <asm/timer.h>
Heiko Carstens5a489b92006-10-06 16:38:35 +020025#include <asm/irq_regs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070026
Linus Torvalds1da177e2005-04-16 15:20:36 -070027static ext_int_info_t ext_int_info_timer;
Heiko Carstens2b67fc42007-02-05 21:16:47 +010028static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -070029
Linus Torvalds1da177e2005-04-16 15:20:36 -070030/*
31 * Update process times based on virtual cpu times stored by entry.S
32 * to the lowcore fields user_timer, system_timer & steal_clock.
33 */
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010034static void do_account_vtime(struct task_struct *tsk, int hardirq_offset)
Linus Torvalds1da177e2005-04-16 15:20:36 -070035{
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010036 struct thread_info *ti = task_thread_info(tsk);
37 __u64 timer, clock, user, system, steal;
Linus Torvalds1da177e2005-04-16 15:20:36 -070038
39 timer = S390_lowcore.last_update_timer;
40 clock = S390_lowcore.last_update_clock;
41 asm volatile (" STPT %0\n" /* Store current cpu timer value */
42 " STCK %1" /* Store current tod clock value */
43 : "=m" (S390_lowcore.last_update_timer),
44 "=m" (S390_lowcore.last_update_clock) );
45 S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010046 S390_lowcore.steal_timer += S390_lowcore.last_update_clock - clock;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010048 user = S390_lowcore.user_timer - ti->user_timer;
49 S390_lowcore.steal_timer -= user;
50 ti->user_timer = S390_lowcore.user_timer;
51 account_user_time(tsk, user, user);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010053 system = S390_lowcore.system_timer - ti->system_timer;
54 S390_lowcore.steal_timer -= system;
55 ti->system_timer = S390_lowcore.system_timer;
Martin Schwidefsky79741dd2008-12-31 15:11:38 +010056 if (idle_task(smp_processor_id()) != current)
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010057 account_system_time(tsk, hardirq_offset, system, system);
Martin Schwidefsky79741dd2008-12-31 15:11:38 +010058 else
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010059 account_idle_time(system);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010061 steal = S390_lowcore.steal_timer;
62 if ((s64) steal > 0) {
63 S390_lowcore.steal_timer = 0;
Martin Schwidefsky79741dd2008-12-31 15:11:38 +010064 if (idle_task(smp_processor_id()) != current)
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010065 account_steal_time(steal);
Martin Schwidefsky79741dd2008-12-31 15:11:38 +010066 else
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010067 account_idle_time(steal);
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 }
Linus Torvalds1da177e2005-04-16 15:20:36 -070069}
70
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010071void account_vtime(struct task_struct *prev, struct task_struct *next)
Martin Schwidefsky1f1c12a2006-01-14 13:21:03 -080072{
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010073 struct thread_info *ti;
Martin Schwidefsky1f1c12a2006-01-14 13:21:03 -080074
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010075 do_account_vtime(prev, 0);
76 ti = task_thread_info(prev);
77 ti->user_timer = S390_lowcore.user_timer;
78 ti->system_timer = S390_lowcore.system_timer;
79 ti = task_thread_info(next);
80 S390_lowcore.user_timer = ti->user_timer;
81 S390_lowcore.system_timer = ti->system_timer;
82}
Martin Schwidefsky1f1c12a2006-01-14 13:21:03 -080083
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010084void account_process_tick(struct task_struct *tsk, int user_tick)
85{
86 do_account_vtime(tsk, HARDIRQ_OFFSET);
Martin Schwidefsky1f1c12a2006-01-14 13:21:03 -080087}
88
89/*
90 * Update process times based on virtual cpu times stored by entry.S
91 * to the lowcore fields user_timer, system_timer & steal_clock.
92 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070093void account_system_vtime(struct task_struct *tsk)
94{
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +010095 struct thread_info *ti = task_thread_info(tsk);
96 __u64 timer, system;
Linus Torvalds1da177e2005-04-16 15:20:36 -070097
98 timer = S390_lowcore.last_update_timer;
99 asm volatile (" STPT %0" /* Store current cpu timer value */
100 : "=m" (S390_lowcore.last_update_timer) );
101 S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
102
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +0100103 system = S390_lowcore.system_timer - ti->system_timer;
104 S390_lowcore.steal_timer -= system;
105 ti->system_timer = S390_lowcore.system_timer;
Martin Schwidefsky79741dd2008-12-31 15:11:38 +0100106 if (in_irq() || idle_task(smp_processor_id()) != current)
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +0100107 account_system_time(tsk, 0, system, system);
Martin Schwidefsky79741dd2008-12-31 15:11:38 +0100108 else
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +0100109 account_idle_time(system);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700110}
Heiko Carstensb0c632d2008-03-25 18:47:20 +0100111EXPORT_SYMBOL_GPL(account_system_vtime);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112
113static inline void set_vtimer(__u64 expires)
114{
115 __u64 timer;
116
117 asm volatile (" STPT %0\n" /* Store current cpu timer value */
118 " SPT %1" /* Set new value immediatly afterwards */
119 : "=m" (timer) : "m" (expires) );
120 S390_lowcore.system_timer += S390_lowcore.last_update_timer - timer;
121 S390_lowcore.last_update_timer = expires;
122
123 /* store expire time for this CPU timer */
Jan Glauberdb77aa52007-04-27 16:01:55 +0200124 __get_cpu_var(virt_cpu_timer).to_expire = expires;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700125}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700126
Heiko Carstens773922e2008-07-14 09:59:06 +0200127void vtime_start_cpu_timer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128{
129 struct vtimer_queue *vt_list;
130
Jan Glauberdb77aa52007-04-27 16:01:55 +0200131 vt_list = &__get_cpu_var(virt_cpu_timer);
Martin Schwidefsky4b7e0702005-05-01 08:58:57 -0700132
133 /* CPU timer interrupt is pending, don't reprogramm it */
134 if (vt_list->idle & 1LL<<63)
135 return;
136
137 if (!list_empty(&vt_list->list))
138 set_vtimer(vt_list->idle);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139}
140
Heiko Carstens773922e2008-07-14 09:59:06 +0200141void vtime_stop_cpu_timer(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143 struct vtimer_queue *vt_list;
144
Jan Glauberdb77aa52007-04-27 16:01:55 +0200145 vt_list = &__get_cpu_var(virt_cpu_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
147 /* nothing to do */
148 if (list_empty(&vt_list->list)) {
149 vt_list->idle = VTIMER_MAX_SLICE;
150 goto fire;
151 }
152
Martin Schwidefsky4b7e0702005-05-01 08:58:57 -0700153 /* store the actual expire value */
154 asm volatile ("STPT %0" : "=m" (vt_list->idle));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700155
156 /*
Martin Schwidefsky4b7e0702005-05-01 08:58:57 -0700157 * If the CPU timer is negative we don't reprogramm
158 * it because we will get instantly an interrupt.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700159 */
Martin Schwidefsky4b7e0702005-05-01 08:58:57 -0700160 if (vt_list->idle & 1LL<<63)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162
Martin Schwidefsky4b7e0702005-05-01 08:58:57 -0700163 vt_list->offset += vt_list->to_expire - vt_list->idle;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164
165 /*
166 * We cannot halt the CPU timer, we just write a value that
167 * nearly never expires (only after 71 years) and re-write
168 * the stored expire value if we continue the timer
169 */
170 fire:
171 set_vtimer(VTIMER_MAX_SLICE);
172}
173
174/*
175 * Sorted add to a list. List is linear searched until first bigger
176 * element is found.
177 */
178static void list_add_sorted(struct vtimer_list *timer, struct list_head *head)
179{
180 struct vtimer_list *event;
181
182 list_for_each_entry(event, head, entry) {
183 if (event->expires > timer->expires) {
184 list_add_tail(&timer->entry, &event->entry);
185 return;
186 }
187 }
188 list_add_tail(&timer->entry, head);
189}
190
191/*
192 * Do the callback functions of expired vtimer events.
193 * Called from within the interrupt handler.
194 */
Heiko Carstens9d0a57c2006-10-11 15:31:26 +0200195static void do_callbacks(struct list_head *cb_list)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700196{
197 struct vtimer_queue *vt_list;
198 struct vtimer_list *event, *tmp;
Heiko Carstens9d0a57c2006-10-11 15:31:26 +0200199 void (*fn)(unsigned long);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 unsigned long data;
201
202 if (list_empty(cb_list))
203 return;
204
Jan Glauberdb77aa52007-04-27 16:01:55 +0200205 vt_list = &__get_cpu_var(virt_cpu_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206
207 list_for_each_entry_safe(event, tmp, cb_list, entry) {
208 fn = event->function;
209 data = event->data;
Heiko Carstens9d0a57c2006-10-11 15:31:26 +0200210 fn(data);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211
212 if (!event->interval)
213 /* delete one shot timer */
214 list_del_init(&event->entry);
215 else {
216 /* move interval timer back to list */
217 spin_lock(&vt_list->lock);
218 list_del_init(&event->entry);
219 list_add_sorted(event, &vt_list->list);
220 spin_unlock(&vt_list->lock);
221 }
222 }
223}
224
225/*
226 * Handler for the virtual CPU timer.
227 */
Heiko Carstens5a489b92006-10-06 16:38:35 +0200228static void do_cpu_timer_interrupt(__u16 error_code)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 __u64 next, delta;
231 struct vtimer_queue *vt_list;
232 struct vtimer_list *event, *tmp;
233 struct list_head *ptr;
234 /* the callback queue */
235 struct list_head cb_list;
236
237 INIT_LIST_HEAD(&cb_list);
Jan Glauberdb77aa52007-04-27 16:01:55 +0200238 vt_list = &__get_cpu_var(virt_cpu_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700239
240 /* walk timer list, fire all expired events */
241 spin_lock(&vt_list->lock);
242
243 if (vt_list->to_expire < VTIMER_MAX_SLICE)
244 vt_list->offset += vt_list->to_expire;
245
246 list_for_each_entry_safe(event, tmp, &vt_list->list, entry) {
247 if (event->expires > vt_list->offset)
248 /* found first unexpired event, leave */
249 break;
250
251 /* re-charge interval timer, we have to add the offset */
252 if (event->interval)
253 event->expires = event->interval + vt_list->offset;
254
255 /* move expired timer to the callback queue */
256 list_move_tail(&event->entry, &cb_list);
257 }
258 spin_unlock(&vt_list->lock);
Heiko Carstens9d0a57c2006-10-11 15:31:26 +0200259 do_callbacks(&cb_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700260
261 /* next event is first in list */
262 spin_lock(&vt_list->lock);
263 if (!list_empty(&vt_list->list)) {
264 ptr = vt_list->list.next;
265 event = list_entry(ptr, struct vtimer_list, entry);
266 next = event->expires - vt_list->offset;
267
268 /* add the expired time from this interrupt handler
269 * and the callback functions
270 */
271 asm volatile ("STPT %0" : "=m" (delta));
272 delta = 0xffffffffffffffffLL - delta + 1;
273 vt_list->offset += delta;
274 next -= delta;
275 } else {
276 vt_list->offset = 0;
277 next = VTIMER_MAX_SLICE;
278 }
279 spin_unlock(&vt_list->lock);
280 set_vtimer(next);
281}
282
283void init_virt_timer(struct vtimer_list *timer)
284{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700285 timer->function = NULL;
286 INIT_LIST_HEAD(&timer->entry);
287 spin_lock_init(&timer->lock);
288}
289EXPORT_SYMBOL(init_virt_timer);
290
Linus Torvalds1da177e2005-04-16 15:20:36 -0700291static inline int vtimer_pending(struct vtimer_list *timer)
292{
293 return (!list_empty(&timer->entry));
294}
295
296/*
297 * this function should only run on the specified CPU
298 */
299static void internal_add_vtimer(struct vtimer_list *timer)
300{
301 unsigned long flags;
302 __u64 done;
303 struct vtimer_list *event;
304 struct vtimer_queue *vt_list;
305
306 vt_list = &per_cpu(virt_cpu_timer, timer->cpu);
307 spin_lock_irqsave(&vt_list->lock, flags);
308
Martin Schwidefskyca366a32008-07-14 09:59:23 +0200309 BUG_ON(timer->cpu != smp_processor_id());
Linus Torvalds1da177e2005-04-16 15:20:36 -0700310
311 /* if list is empty we only have to set the timer */
312 if (list_empty(&vt_list->list)) {
313 /* reset the offset, this may happen if the last timer was
314 * just deleted by mod_virt_timer and the interrupt
315 * didn't happen until here
316 */
317 vt_list->offset = 0;
318 goto fire;
319 }
320
321 /* save progress */
322 asm volatile ("STPT %0" : "=m" (done));
323
324 /* calculate completed work */
325 done = vt_list->to_expire - done + vt_list->offset;
326 vt_list->offset = 0;
327
328 list_for_each_entry(event, &vt_list->list, entry)
329 event->expires -= done;
330
331 fire:
332 list_add_sorted(timer, &vt_list->list);
333
334 /* get first element, which is the next vtimer slice */
335 event = list_entry(vt_list->list.next, struct vtimer_list, entry);
336
337 set_vtimer(event->expires);
338 spin_unlock_irqrestore(&vt_list->lock, flags);
Andreas Mohrd6e05ed2006-06-26 18:35:02 +0200339 /* release CPU acquired in prepare_vtimer or mod_virt_timer() */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700340 put_cpu();
341}
342
Martin Schwidefskyca366a32008-07-14 09:59:23 +0200343static inline void prepare_vtimer(struct vtimer_list *timer)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700344{
Martin Schwidefskyca366a32008-07-14 09:59:23 +0200345 BUG_ON(!timer->function);
346 BUG_ON(!timer->expires || timer->expires > VTIMER_MAX_SLICE);
347 BUG_ON(vtimer_pending(timer));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700348 timer->cpu = get_cpu();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349}
350
351/*
352 * add_virt_timer - add an oneshot virtual CPU timer
353 */
354void add_virt_timer(void *new)
355{
356 struct vtimer_list *timer;
357
358 timer = (struct vtimer_list *)new;
Martin Schwidefskyca366a32008-07-14 09:59:23 +0200359 prepare_vtimer(timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 timer->interval = 0;
361 internal_add_vtimer(timer);
362}
363EXPORT_SYMBOL(add_virt_timer);
364
365/*
366 * add_virt_timer_int - add an interval virtual CPU timer
367 */
368void add_virt_timer_periodic(void *new)
369{
370 struct vtimer_list *timer;
371
372 timer = (struct vtimer_list *)new;
Martin Schwidefskyca366a32008-07-14 09:59:23 +0200373 prepare_vtimer(timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700374 timer->interval = timer->expires;
375 internal_add_vtimer(timer);
376}
377EXPORT_SYMBOL(add_virt_timer_periodic);
378
379/*
380 * If we change a pending timer the function must be called on the CPU
Heiko Carstens3bb447f2007-07-27 12:29:08 +0200381 * where the timer is running on, e.g. by smp_call_function_single()
Linus Torvalds1da177e2005-04-16 15:20:36 -0700382 *
383 * The original mod_timer adds the timer if it is not pending. For compatibility
384 * we do the same. The timer will be added on the current CPU as a oneshot timer.
385 *
386 * returns whether it has modified a pending timer (1) or not (0)
387 */
388int mod_virt_timer(struct vtimer_list *timer, __u64 expires)
389{
390 struct vtimer_queue *vt_list;
391 unsigned long flags;
392 int cpu;
393
Martin Schwidefskyca366a32008-07-14 09:59:23 +0200394 BUG_ON(!timer->function);
395 BUG_ON(!expires || expires > VTIMER_MAX_SLICE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396
397 /*
398 * This is a common optimization triggered by the
399 * networking code - if the timer is re-modified
400 * to be the same thing then just return:
401 */
402 if (timer->expires == expires && vtimer_pending(timer))
403 return 1;
404
405 cpu = get_cpu();
406 vt_list = &per_cpu(virt_cpu_timer, cpu);
407
Martin Schwidefskyca366a32008-07-14 09:59:23 +0200408 /* check if we run on the right CPU */
409 BUG_ON(timer->cpu != cpu);
410
Linus Torvalds1da177e2005-04-16 15:20:36 -0700411 /* disable interrupts before test if timer is pending */
412 spin_lock_irqsave(&vt_list->lock, flags);
413
414 /* if timer isn't pending add it on the current CPU */
415 if (!vtimer_pending(timer)) {
416 spin_unlock_irqrestore(&vt_list->lock, flags);
417 /* we do not activate an interval timer with mod_virt_timer */
418 timer->interval = 0;
419 timer->expires = expires;
420 timer->cpu = cpu;
421 internal_add_vtimer(timer);
422 return 0;
423 }
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 list_del_init(&timer->entry);
426 timer->expires = expires;
427
428 /* also change the interval if we have an interval timer */
429 if (timer->interval)
430 timer->interval = expires;
431
432 /* the timer can't expire anymore so we can release the lock */
433 spin_unlock_irqrestore(&vt_list->lock, flags);
434 internal_add_vtimer(timer);
435 return 1;
436}
437EXPORT_SYMBOL(mod_virt_timer);
438
439/*
440 * delete a virtual timer
441 *
442 * returns whether the deleted timer was pending (1) or not (0)
443 */
444int del_virt_timer(struct vtimer_list *timer)
445{
446 unsigned long flags;
447 struct vtimer_queue *vt_list;
448
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 /* check if timer is pending */
450 if (!vtimer_pending(timer))
451 return 0;
452
453 vt_list = &per_cpu(virt_cpu_timer, timer->cpu);
454 spin_lock_irqsave(&vt_list->lock, flags);
455
456 /* we don't interrupt a running timer, just let it expire! */
457 list_del_init(&timer->entry);
458
459 /* last timer removed */
460 if (list_empty(&vt_list->list)) {
461 vt_list->to_expire = 0;
462 vt_list->offset = 0;
463 }
464
465 spin_unlock_irqrestore(&vt_list->lock, flags);
466 return 1;
467}
468EXPORT_SYMBOL(del_virt_timer);
469
470/*
471 * Start the virtual CPU timer on the current CPU.
472 */
473void init_cpu_vtimer(void)
474{
475 struct vtimer_queue *vt_list;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700476
477 /* kick the virtual timer */
478 S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
479 S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
Martin Schwidefskyaa5e97c2008-12-31 15:11:39 +0100481 asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
Martin Schwidefskyd54853e2007-02-05 21:18:19 +0100482
483 /* enable cpu timer interrupts */
484 __ctl_set_bit(0,10);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485
Jan Glauberdb77aa52007-04-27 16:01:55 +0200486 vt_list = &__get_cpu_var(virt_cpu_timer);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 INIT_LIST_HEAD(&vt_list->list);
488 spin_lock_init(&vt_list->lock);
489 vt_list->to_expire = 0;
490 vt_list->offset = 0;
491 vt_list->idle = 0;
492
493}
494
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495void __init vtime_init(void)
496{
497 /* request the cpu timer external interrupt */
498 if (register_early_external_interrupt(0x1005, do_cpu_timer_interrupt,
499 &ext_int_info_timer) != 0)
500 panic("Couldn't request external interrupt 0x1005");
501
Martin Schwidefskyd54853e2007-02-05 21:18:19 +0100502 /* Enable cpu timer interrupts on the boot cpu. */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 init_cpu_vtimer();
504}
505