[PATCH] idle cputime accounting
[safe/jmp/linux-2.6] / arch / s390 / kernel / vtime.c
index 1d7d393..4a4a34c 100644 (file)
 #include <asm/irq_regs.h>
 
 static ext_int_info_t ext_int_info_timer;
-DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
+static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
 
-#ifdef CONFIG_VIRT_CPU_ACCOUNTING
 /*
  * Update process times based on virtual cpu times stored by entry.S
  * to the lowcore fields user_timer, system_timer & steal_clock.
  */
-void account_tick_vtime(struct task_struct *tsk)
+void account_process_tick(struct task_struct *tsk, int user_tick)
 {
        cputime_t cputime;
        __u64 timer, clock;
@@ -51,25 +50,25 @@ void account_tick_vtime(struct task_struct *tsk)
        rcu_user_flag = cputime != 0;
        S390_lowcore.user_timer -= cputime << 12;
        S390_lowcore.steal_clock -= cputime << 12;
-       account_user_time(tsk, cputime);
+       account_user_time(tsk, cputime, cputime);
 
        cputime =  S390_lowcore.system_timer >> 12;
        S390_lowcore.system_timer -= cputime << 12;
        S390_lowcore.steal_clock -= cputime << 12;
-       account_system_time(tsk, HARDIRQ_OFFSET, cputime);
+       if (idle_task(smp_processor_id()) != current)
+               account_system_time(tsk, HARDIRQ_OFFSET, cputime, cputime);
+       else
+               account_idle_time(cputime);
 
        cputime = S390_lowcore.steal_clock;
        if ((__s64) cputime > 0) {
                cputime >>= 12;
                S390_lowcore.steal_clock -= cputime << 12;
-               account_steal_time(tsk, cputime);
+               if (idle_task(smp_processor_id()) != current)
+                       account_steal_time(cputime);
+               else
+                       account_idle_time(cputime);
        }
-
-       run_local_timers();
-       if (rcu_pending(smp_processor_id()))
-               rcu_check_callbacks(smp_processor_id(), rcu_user_flag);
-       scheduler_tick();
-       run_posix_cpu_timers(tsk);
 }
 
 /*
@@ -89,12 +88,15 @@ void account_vtime(struct task_struct *tsk)
        cputime = S390_lowcore.user_timer >> 12;
        S390_lowcore.user_timer -= cputime << 12;
        S390_lowcore.steal_clock -= cputime << 12;
-       account_user_time(tsk, cputime);
+       account_user_time(tsk, cputime, cputime);
 
        cputime =  S390_lowcore.system_timer >> 12;
        S390_lowcore.system_timer -= cputime << 12;
        S390_lowcore.steal_clock -= cputime << 12;
-       account_system_time(tsk, 0, cputime);
+       if (idle_task(smp_processor_id()) != current)
+               account_system_time(tsk, 0, cputime, cputime);
+       else
+               account_idle_time(cputime);
 }
 
 /*
@@ -114,8 +116,12 @@ void account_system_vtime(struct task_struct *tsk)
        cputime =  S390_lowcore.system_timer >> 12;
        S390_lowcore.system_timer -= cputime << 12;
        S390_lowcore.steal_clock -= cputime << 12;
-       account_system_time(tsk, 0, cputime);
+       if (in_irq() || idle_task(smp_processor_id()) != current)
+               account_system_time(tsk, 0, cputime, cputime);
+       else
+               account_idle_time(cputime);
 }
+EXPORT_SYMBOL_GPL(account_system_vtime);
 
 static inline void set_vtimer(__u64 expires)
 {
@@ -128,24 +134,14 @@ static inline void set_vtimer(__u64 expires)
        S390_lowcore.last_update_timer = expires;
 
        /* store expire time for this CPU timer */
-       per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires;
-}
-#else
-static inline void set_vtimer(__u64 expires)
-{
-       S390_lowcore.last_update_timer = expires;
-       asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
-
-       /* store expire time for this CPU timer */
-       per_cpu(virt_cpu_timer, smp_processor_id()).to_expire = expires;
+       __get_cpu_var(virt_cpu_timer).to_expire = expires;
 }
-#endif
 
-static void start_cpu_timer(void)
+void vtime_start_cpu_timer(void)
 {
        struct vtimer_queue *vt_list;
 
-       vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
+       vt_list = &__get_cpu_var(virt_cpu_timer);
 
        /* CPU timer interrupt is pending, don't reprogramm it */
        if (vt_list->idle & 1LL<<63)
@@ -155,11 +151,11 @@ static void start_cpu_timer(void)
                set_vtimer(vt_list->idle);
 }
 
-static void stop_cpu_timer(void)
+void vtime_stop_cpu_timer(void)
 {
        struct vtimer_queue *vt_list;
 
-       vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
+       vt_list = &__get_cpu_var(virt_cpu_timer);
 
        /* nothing to do */
        if (list_empty(&vt_list->list)) {
@@ -209,22 +205,22 @@ static void list_add_sorted(struct vtimer_list *timer, struct list_head *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)
+static void do_callbacks(struct list_head *cb_list)
 {
        struct vtimer_queue *vt_list;
        struct vtimer_list *event, *tmp;
-       void (*fn)(unsigned long, struct pt_regs*);
+       void (*fn)(unsigned long);
        unsigned long data;
 
        if (list_empty(cb_list))
                return;
 
-       vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
+       vt_list = &__get_cpu_var(virt_cpu_timer);
 
        list_for_each_entry_safe(event, tmp, cb_list, entry) {
                fn = event->function;
                data = event->data;
-               fn(data, regs);
+               fn(data);
 
                if (!event->interval)
                        /* delete one shot timer */
@@ -244,7 +240,6 @@ static void do_callbacks(struct list_head *cb_list, struct pt_regs *regs)
  */
 static void do_cpu_timer_interrupt(__u16 error_code)
 {
-       int cpu;
        __u64 next, delta;
        struct vtimer_queue *vt_list;
        struct vtimer_list *event, *tmp;
@@ -253,8 +248,7 @@ static void do_cpu_timer_interrupt(__u16 error_code)
        struct list_head cb_list;
 
        INIT_LIST_HEAD(&cb_list);
-       cpu = smp_processor_id();
-       vt_list = &per_cpu(virt_cpu_timer, cpu);
+       vt_list = &__get_cpu_var(virt_cpu_timer);
 
        /* walk timer list, fire all expired events */
        spin_lock(&vt_list->lock);
@@ -275,7 +269,7 @@ static void do_cpu_timer_interrupt(__u16 error_code)
                list_move_tail(&event->entry, &cb_list);
        }
        spin_unlock(&vt_list->lock);
-       do_callbacks(&cb_list, get_irq_regs());
+       do_callbacks(&cb_list);
 
        /* next event is first in list */
        spin_lock(&vt_list->lock);
@@ -325,8 +319,7 @@ static void internal_add_vtimer(struct vtimer_list *timer)
        vt_list = &per_cpu(virt_cpu_timer, timer->cpu);
        spin_lock_irqsave(&vt_list->lock, flags);
 
-       if (timer->cpu != smp_processor_id())
-               printk("internal_add_vtimer: BUG, running on wrong CPU");
+       BUG_ON(timer->cpu != smp_processor_id());
 
        /* if list is empty we only have to set the timer */
        if (list_empty(&vt_list->list)) {
@@ -360,25 +353,12 @@ static void internal_add_vtimer(struct vtimer_list *timer)
        put_cpu();
 }
 
-static inline int prepare_vtimer(struct vtimer_list *timer)
+static inline void prepare_vtimer(struct vtimer_list *timer)
 {
-       if (!timer->function) {
-               printk("add_virt_timer: uninitialized timer\n");
-               return -EINVAL;
-       }
-
-       if (!timer->expires || timer->expires > VTIMER_MAX_SLICE) {
-               printk("add_virt_timer: invalid timer expire value!\n");
-               return -EINVAL;
-       }
-
-       if (vtimer_pending(timer)) {
-               printk("add_virt_timer: timer pending\n");
-               return -EBUSY;
-       }
-
+       BUG_ON(!timer->function);
+       BUG_ON(!timer->expires || timer->expires > VTIMER_MAX_SLICE);
+       BUG_ON(vtimer_pending(timer));
        timer->cpu = get_cpu();
-       return 0;
 }
 
 /*
@@ -389,10 +369,7 @@ void add_virt_timer(void *new)
        struct vtimer_list *timer;
 
        timer = (struct vtimer_list *)new;
-
-       if (prepare_vtimer(timer) < 0)
-               return;
-
+       prepare_vtimer(timer);
        timer->interval = 0;
        internal_add_vtimer(timer);
 }
@@ -406,10 +383,7 @@ void add_virt_timer_periodic(void *new)
        struct vtimer_list *timer;
 
        timer = (struct vtimer_list *)new;
-
-       if (prepare_vtimer(timer) < 0)
-               return;
-
+       prepare_vtimer(timer);
        timer->interval = timer->expires;
        internal_add_vtimer(timer);
 }
@@ -417,7 +391,7 @@ EXPORT_SYMBOL(add_virt_timer_periodic);
 
 /*
  * If we change a pending timer the function must be called on the CPU
- * where the timer is running on, e.g. by smp_call_function_on()
+ * where the timer is running on, e.g. by smp_call_function_single()
  *
  * The original mod_timer adds the timer if it is not pending. For compatibility
  * we do the same. The timer will be added on the current CPU as a oneshot timer.
@@ -430,15 +404,8 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires)
        unsigned long flags;
        int cpu;
 
-       if (!timer->function) {
-               printk("mod_virt_timer: uninitialized timer\n");
-               return  -EINVAL;
-       }
-
-       if (!expires || expires > VTIMER_MAX_SLICE) {
-               printk("mod_virt_timer: invalid expire range\n");
-               return -EINVAL;
-       }
+       BUG_ON(!timer->function);
+       BUG_ON(!expires || expires > VTIMER_MAX_SLICE);
 
        /*
         * This is a common optimization triggered by the
@@ -451,6 +418,9 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires)
        cpu = get_cpu();
        vt_list = &per_cpu(virt_cpu_timer, cpu);
 
+       /* check if we run on the right CPU */
+       BUG_ON(timer->cpu != cpu);
+
        /* disable interrupts before test if timer is pending */
        spin_lock_irqsave(&vt_list->lock, flags);
 
@@ -465,14 +435,6 @@ int mod_virt_timer(struct vtimer_list *timer, __u64 expires)
                return 0;
        }
 
-       /* check if we run on the right CPU */
-       if (timer->cpu != cpu) {
-               printk("mod_virt_timer: running on wrong CPU, check your code\n");
-               spin_unlock_irqrestore(&vt_list->lock, flags);
-               put_cpu();
-               return -EINVAL;
-       }
-
        list_del_init(&timer->entry);
        timer->expires = expires;
 
@@ -524,18 +486,17 @@ EXPORT_SYMBOL(del_virt_timer);
 void init_cpu_vtimer(void)
 {
        struct vtimer_queue *vt_list;
-       unsigned long cr0;
 
        /* kick the virtual timer */
        S390_lowcore.exit_timer = VTIMER_MAX_SLICE;
        S390_lowcore.last_update_timer = VTIMER_MAX_SLICE;
        asm volatile ("SPT %0" : : "m" (S390_lowcore.last_update_timer));
        asm volatile ("STCK %0" : "=m" (S390_lowcore.last_update_clock));
-       __ctl_store(cr0, 0, 0);
-       cr0 |= 0x400;
-       __ctl_load(cr0, 0, 0);
 
-       vt_list = &per_cpu(virt_cpu_timer, smp_processor_id());
+       /* enable cpu timer interrupts */
+       __ctl_set_bit(0,10);
+
+       vt_list = &__get_cpu_var(virt_cpu_timer);
        INIT_LIST_HEAD(&vt_list->list);
        spin_lock_init(&vt_list->lock);
        vt_list->to_expire = 0;
@@ -544,24 +505,6 @@ void init_cpu_vtimer(void)
 
 }
 
-static int vtimer_idle_notify(struct notifier_block *self,
-                             unsigned long action, void *hcpu)
-{
-       switch (action) {
-       case CPU_IDLE:
-               stop_cpu_timer();
-               break;
-       case CPU_NOT_IDLE:
-               start_cpu_timer();
-               break;
-       }
-       return NOTIFY_OK;
-}
-
-static struct notifier_block vtimer_idle_nb = {
-       .notifier_call = vtimer_idle_notify,
-};
-
 void __init vtime_init(void)
 {
        /* request the cpu timer external interrupt */
@@ -569,9 +512,7 @@ void __init vtime_init(void)
                                              &ext_int_info_timer) != 0)
                panic("Couldn't request external interrupt 0x1005");
 
-       if (register_idle_notifier(&vtimer_idle_nb))
-               panic("Couldn't register idle notifier");
-
+       /* Enable cpu timer interrupts on the boot cpu. */
        init_cpu_vtimer();
 }