natsemi: Avoid IntrStatus lossage if RX state machine resets.
[powerpc.git] / kernel / timer.c
index 6d843e1..797cccb 100644 (file)
@@ -34,6 +34,8 @@
 #include <linux/cpu.h>
 #include <linux/syscalls.h>
 #include <linux/delay.h>
+#include <linux/tick.h>
+#include <linux/kallsyms.h>
 
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
@@ -262,6 +264,18 @@ static void internal_add_timer(tvec_base_t *base, struct timer_list *timer)
        list_add_tail(&timer->entry, vec);
 }
 
+#ifdef CONFIG_TIMER_STATS
+void __timer_stats_timer_set_start_info(struct timer_list *timer, void *addr)
+{
+       if (timer->start_site)
+               return;
+
+       timer->start_site = addr;
+       memcpy(timer->start_comm, current->comm, TASK_COMM_LEN);
+       timer->start_pid = current->pid;
+}
+#endif
+
 /**
  * init_timer - initialize a timer.
  * @timer: the timer to be initialized
@@ -273,11 +287,16 @@ void fastcall init_timer(struct timer_list *timer)
 {
        timer->entry.next = NULL;
        timer->base = __raw_get_cpu_var(tvec_bases);
+#ifdef CONFIG_TIMER_STATS
+       timer->start_site = NULL;
+       timer->start_pid = -1;
+       memset(timer->start_comm, 0, TASK_COMM_LEN);
+#endif
 }
 EXPORT_SYMBOL(init_timer);
 
 static inline void detach_timer(struct timer_list *timer,
-                                       int clear_pending)
+                               int clear_pending)
 {
        struct list_head *entry = &timer->entry;
 
@@ -324,6 +343,7 @@ int __mod_timer(struct timer_list *timer, unsigned long expires)
        unsigned long flags;
        int ret = 0;
 
+       timer_stats_timer_set_start_info(timer);
        BUG_ON(!timer->function);
 
        base = lock_timer_base(timer, &flags);
@@ -374,6 +394,7 @@ void add_timer_on(struct timer_list *timer, int cpu)
        tvec_base_t *base = per_cpu(tvec_bases, cpu);
        unsigned long flags;
 
+       timer_stats_timer_set_start_info(timer);
        BUG_ON(timer_pending(timer) || !timer->function);
        spin_lock_irqsave(&base->lock, flags);
        timer->base = base;
@@ -406,6 +427,7 @@ int mod_timer(struct timer_list *timer, unsigned long expires)
 {
        BUG_ON(!timer->function);
 
+       timer_stats_timer_set_start_info(timer);
        /*
         * This is a common optimization triggered by the
         * networking code - if the timer is re-modified
@@ -436,6 +458,7 @@ int del_timer(struct timer_list *timer)
        unsigned long flags;
        int ret = 0;
 
+       timer_stats_timer_clear_start_info(timer);
        if (timer_pending(timer)) {
                base = lock_timer_base(timer, &flags);
                if (timer_pending(timer)) {
@@ -569,6 +592,8 @@ static inline void __run_timers(tvec_base_t *base)
                        fn = timer->function;
                        data = timer->data;
 
+                       timer_stats_account_timer(timer);
+
                        set_running_timer(base, timer);
                        detach_timer(timer, 1);
                        spin_unlock_irq(&base->lock);
@@ -686,6 +711,7 @@ static unsigned long cmp_next_hrtimer_event(unsigned long now,
 
 /**
  * next_timer_interrupt - return the jiffy of the next pending timer
+ * @now: current time (in jiffies)
  */
 unsigned long get_next_timer_interrupt(unsigned long now)
 {
@@ -836,6 +862,8 @@ int do_settimeofday(struct timespec *tv)
        clock->error = 0;
        ntp_clear();
 
+       update_vsyscall(&xtime, clock);
+
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
        /* signal hrtimers about time change */
@@ -873,6 +901,8 @@ static void change_clocksource(void)
        clock->xtime_nsec = 0;
        clocksource_calculate_interval(clock, NTP_INTERVAL_LENGTH);
 
+       tick_clock_notify();
+
        printk(KERN_INFO "Time: %s clocksource has been installed.\n",
               clock->name);
 }
@@ -881,7 +911,7 @@ static inline void change_clocksource(void) { }
 #endif
 
 /**
- * timeofday_is_continuous - check to see if timekeeping is free running
+ * timekeeping_is_continuous - check to see if timekeeping is free running
  */
 int timekeeping_is_continuous(void)
 {
@@ -936,7 +966,6 @@ void __init timekeeping_init(void)
        write_sequnlock_irqrestore(&xtime_lock, flags);
 }
 
-
 /* flag for if timekeeping is suspended */
 static int timekeeping_suspended;
 /* time in seconds when suspend began */
@@ -970,7 +999,11 @@ static int timekeeping_resume(struct sys_device *dev)
        write_sequnlock_irqrestore(&xtime_lock, flags);
 
        touch_softlockup_watchdog();
-       hrtimer_notify_resume();
+
+       clockevents_notify(CLOCK_EVT_NOTIFY_RESUME, NULL);
+
+       /* Resume hrtimers */
+       clock_was_set();
 
        return 0;
 }
@@ -983,6 +1016,9 @@ static int timekeeping_suspend(struct sys_device *dev, pm_message_t state)
        timekeeping_suspended = 1;
        timekeeping_suspend_time = read_persistent_clock();
        write_sequnlock_irqrestore(&xtime_lock, flags);
+
+       clockevents_notify(CLOCK_EVT_NOTIFY_SUSPEND, NULL);
+
        return 0;
 }
 
@@ -1147,6 +1183,7 @@ static void update_wall_time(void)
 
        /* check to see if there is a new clocksource to use */
        change_clocksource();
+       update_vsyscall(&xtime, clock);
 }
 
 /*
@@ -1226,7 +1263,8 @@ static void run_timer_softirq(struct softirq_action *h)
 {
        tvec_base_t *base = __get_cpu_var(tvec_bases);
 
-       hrtimer_run_queues();
+       hrtimer_run_queues();
+
        if (time_after_eq(jiffies, base->timer_jiffies))
                __run_timers(base);
 }
@@ -1621,8 +1659,8 @@ static void __devinit migrate_timers(int cpu)
        new_base = get_cpu_var(tvec_bases);
 
        local_irq_disable();
-       spin_lock(&new_base->lock);
-       spin_lock(&old_base->lock);
+       double_spin_lock(&new_base->lock, &old_base->lock,
+                        smp_processor_id() < cpu);
 
        BUG_ON(old_base->running_timer);
 
@@ -1635,8 +1673,8 @@ static void __devinit migrate_timers(int cpu)
                migrate_timer_list(new_base, old_base->tv5.vec + i);
        }
 
-       spin_unlock(&old_base->lock);
-       spin_unlock(&new_base->lock);
+       double_spin_unlock(&new_base->lock, &old_base->lock,
+                          smp_processor_id() < cpu);
        local_irq_enable();
        put_cpu_var(tvec_bases);
 }
@@ -1672,6 +1710,8 @@ void __init init_timers(void)
        int err = timer_cpu_notify(&timers_nb, (unsigned long)CPU_UP_PREPARE,
                                (void *)(long)smp_processor_id());
 
+       init_timer_stats();
+
        BUG_ON(err == NOTIFY_BAD);
        register_cpu_notifier(&timers_nb);
        open_softirq(TIMER_SOFTIRQ, run_timer_softirq, NULL);