-#ifdef CONFIG_VIRT_TIMER
-void start_cpu_timer(void)
-{
- struct vtimer_queue *vt_list;
-
- vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
- set_vtimer(vt_list->idle);
-}
-
-int stop_cpu_timer(void)
-{
- __u64 done;
- struct vtimer_queue *vt_list;
-
- vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
-
- /* nothing to do */
- if (list_empty(&vt_list->list)) {
- vt_list->idle = VTIMER_MAX_SLICE;
- goto fire;
- }
-
- /* store progress */
- asm volatile ("STPT %0" : "=m" (done));
-
- /*
- * If done is negative we do not stop the CPU timer
- * because we will get instantly an interrupt that
- * will start the CPU timer again.
- */
- if (done & 1LL<<63)
- return 1;
- else
- vt_list->offset += vt_list->to_expire - done;
-
- /* save the actual expire value */
- vt_list->idle = done;
-
- /*
- * We cannot halt the CPU timer, we just write a value that
- * nearly never expires (only after 71 years) and re-write
- * the stored expire value if we continue the timer
- */
- fire:
- set_vtimer(VTIMER_MAX_SLICE);
- return 0;
-}
-
-void set_vtimer(__u64 expires)
-{
- asm volatile ("SPT %0" : : "m" (expires));
-
- /* store expire time for this CPU timer */
- per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires;
-}
-
-/*
- * Sorted add to a list. List is linear searched until first bigger
- * element is found.
- */
-void list_add_sorted(struct vtimer_list *timer, struct list_head *head)
-{
- struct vtimer_list *event;
-
- list_for_each_entry(event, head, entry) {
- if (event->expires > timer->expires) {
- list_add_tail(&timer->entry, &event->entry);
- return;
- }
- }
- list_add_tail(&timer->entry, head);
-}
-
-/*
- * Do the callback functions of expired vtimer events.
- * Called from within the interrupt handler.
- */
-static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs)
-{
- struct vtimer_queue *vt_list;
- struct vtimer_list *event, *tmp;
- void (*fn)(unsigned long, struct pt_regs*);
- unsigned long data;
-
- if (list_empty(cb_list))
- return;
-
- vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
-
- list_for_each_entry_safe(event, tmp, cb_list, entry) {
- fn = event->function;
- data = event->data;
- fn(data, regs);
-
- if (!event->interval)
- /* delete one shot timer */
- list_del_init(&event->entry);
- else {
- /* move interval timer back to list */
- spin_lock(&vt_list->lock);
- list_del_init(&event->entry);
- list_add_sorted(event, &vt_list->list);
- spin_unlock(&vt_list->lock);
- }
- }
-}
-
-/*
- * Handler for the virtual CPU timer.
- */
-static void do_cpu_timer_interrupt(struct pt_regs *regs, __u16 error_code)
-{
- int cpu;
- __u64 next, delta;
- struct vtimer_queue *vt_list;
- struct vtimer_list *event, *tmp;
- struct list_head *ptr;
- /* the callback queue */
- struct list_head cb_list;
-
- INIT_LIST_HEAD(&cb_list);
- cpu = smp_processor_id();
- vt_list = &per_cpu(virt_cpu_timer, cpu);
-
- /* walk timer list, fire all expired events */
- spin_lock(&vt_list->lock);
-
- if (vt_list->to_expire < VTIMER_MAX_SLICE)
- vt_list->offset += vt_list->to_expire;
-
- list_for_each_entry_safe(event, tmp, &vt_list->list, entry) {
- if (event->expires > vt_list->offset)
- /* found first unexpired event, leave */
- break;
-
- /* re-charge interval timer, we have to add the offset */
- if (event->interval)
- event->expires = event->interval + vt_list->offset;
-
- /* move expired timer to the callback queue */
- list_move_tail(&event->entry, &cb_list);
- }
- spin_unlock(&vt_list->lock);
- do_callbacks(&cb_list, regs);
-
- /* next event is first in list */
- spin_lock(&vt_list->lock);
- if (!list_empty(&vt_list->list)) {
- ptr = vt_list->list.next;
- event = list_entry(ptr, struct vtimer_list, entry);
- next = event->expires - vt_list->offset;
-
- /* add the expired time from this interrupt handler
- * and the callback functions
- */
- asm volatile ("STPT %0" : "=m" (delta));
- delta = 0xffffffffffffffffLL - delta + 1;
- vt_list->offset += delta;
- next -= delta;
- } else {
- vt_list->offset = 0;
- next = VTIMER_MAX_SLICE;
- }
- spin_unlock(&vt_list->lock);
- set_vtimer(next);
-}
-#endif
-