Merge ../linux-2.6-watchdog-mm
[linux-drm-fsl-dcu.git] / arch / s390 / kernel / time.c
index abab42e9f5f8718cfcda91702803e8d797f70544..6cceed4df73ee40adf6f233d601ae511df9050bc 100644 (file)
 #include <linux/profile.h>
 #include <linux/timex.h>
 #include <linux/notifier.h>
+#include <linux/clocksource.h>
 
 #include <asm/uaccess.h>
 #include <asm/delay.h>
 #include <asm/s390_ext.h>
 #include <asm/div64.h>
 #include <asm/irq.h>
+#include <asm/irq_regs.h>
 #include <asm/timer.h>
 
 /* change this if you have some constant time drift */
@@ -53,8 +55,6 @@ static u64 init_timer_cc;
 static u64 jiffies_timer_cc;
 static u64 xtime_cc;
 
-extern unsigned long wall_jiffies;
-
 /*
  * Scheduler clock - returns current time in nanosec units.
  */
@@ -83,79 +83,10 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime)
        xtime->tv_nsec = ((todval * 1000) >> 12);
 }
 
-static inline unsigned long do_gettimeoffset(void) 
-{
-       __u64 now;
-
-        now = (get_clock() - jiffies_timer_cc) >> 12;
-       /* We require the offset from the latest update of xtime */
-       now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
-       return (unsigned long) now;
-}
-
-/*
- * This version of gettimeofday has microsecond resolution.
- */
-void do_gettimeofday(struct timeval *tv)
-{
-       unsigned long flags;
-       unsigned long seq;
-       unsigned long usec, sec;
-
-       do {
-               seq = read_seqbegin_irqsave(&xtime_lock, flags);
-
-               sec = xtime.tv_sec;
-               usec = xtime.tv_nsec / 1000 + do_gettimeoffset();
-       } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
-
-       while (usec >= 1000000) {
-               usec -= 1000000;
-               sec++;
-       }
-
-       tv->tv_sec = sec;
-       tv->tv_usec = usec;
-}
-
-EXPORT_SYMBOL(do_gettimeofday);
-
-int do_settimeofday(struct timespec *tv)
-{
-       time_t wtm_sec, sec = tv->tv_sec;
-       long wtm_nsec, nsec = tv->tv_nsec;
-
-       if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
-               return -EINVAL;
-
-       write_seqlock_irq(&xtime_lock);
-       /* This is revolting. We need to set the xtime.tv_nsec
-        * correctly. However, the value in this location is
-        * is value at the last tick.
-        * Discover what correction gettimeofday
-        * would have done, and then undo it!
-        */
-       nsec -= do_gettimeoffset() * 1000;
-
-       wtm_sec  = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
-       wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
-
-       set_normalized_timespec(&xtime, sec, nsec);
-       set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
-
-       ntp_clear();
-       write_sequnlock_irq(&xtime_lock);
-       clock_was_set();
-       return 0;
-}
-
-EXPORT_SYMBOL(do_settimeofday);
-
-
 #ifdef CONFIG_PROFILING
-#define s390_do_profile(regs)  profile_tick(CPU_PROFILING, regs)
+#define s390_do_profile()      profile_tick(CPU_PROFILING)
 #else
-#define s390_do_profile(regs)  do { ; } while(0)
+#define s390_do_profile()      do { ; } while(0)
 #endif /* CONFIG_PROFILING */
 
 
@@ -163,7 +94,7 @@ EXPORT_SYMBOL(do_settimeofday);
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "do_timer()" routine every clocktick
  */
-void account_ticks(struct pt_regs *regs)
+void account_ticks(void)
 {
        __u64 tmp;
        __u32 ticks;
@@ -224,10 +155,10 @@ void account_ticks(struct pt_regs *regs)
        account_tick_vtime(current);
 #else
        while (ticks--)
-               update_process_times(user_mode(regs));
+               update_process_times(user_mode(get_irq_regs()));
 #endif
 
-       s390_do_profile(regs);
+       s390_do_profile();
 }
 
 #ifdef CONFIG_NO_IDLE_HZ
@@ -288,9 +219,11 @@ static inline void stop_hz_timer(void)
  */
 static inline void start_hz_timer(void)
 {
+       BUG_ON(!in_interrupt());
+
        if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
                return;
-       account_ticks(task_pt_regs(current));
+       account_ticks();
        cpu_clear(smp_processor_id(), nohz_cpu_mask);
 }
 
@@ -340,6 +273,22 @@ void init_cpu_timer(void)
 
 extern void vtime_init(void);
 
+static cycle_t read_tod_clock(void)
+{
+       return get_clock();
+}
+
+static struct clocksource clocksource_tod = {
+       .name           = "tod",
+       .rating         = 100,
+       .read           = read_tod_clock,
+       .mask           = -1ULL,
+       .mult           = 1000,
+       .shift          = 12,
+       .is_continuous  = 1,
+};
+
+
 /*
  * Initialize the TOD clock and the CPU timer of
  * the boot cpu.
@@ -384,6 +333,9 @@ void __init time_init(void)
                                              &ext_int_info_cc) != 0)
                 panic("Couldn't request external interrupt 0x1004");
 
+       if (clocksource_register(&clocksource_tod) != 0)
+               panic("Could not register TOD clock source");
+
         init_cpu_timer();
 
 #ifdef CONFIG_NO_IDLE_HZ