[PATCH] Time: Use clocksource infrastructure for update_wall_time
authorjohn stultz <johnstul@us.ibm.com>
Mon, 26 Jun 2006 07:25:06 +0000 (00:25 -0700)
committerLinus Torvalds <torvalds@g5.osdl.org>
Mon, 26 Jun 2006 16:58:20 +0000 (09:58 -0700)
Modify the update_wall_time function so it increments time using the
clocksource abstraction instead of jiffies.  Since the only clocksource driver
currently provided is the jiffies clocksource, this should result in no
functional change.  Additionally, a timekeeping_init and timekeeping_resume
function has been added to initialize and maintain some of the new timekeping
state.

[hirofumi@mail.parknet.co.jp: fixlet]
Signed-off-by: John Stultz <johnstul@us.ibm.com>
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
include/linux/time.h
init/main.c
kernel/Makefile
kernel/time/clocksource.c
kernel/timer.c

index 0cd696cee998c0ed24d28ead62335160bc4e47a0..88d3b812841ec2186821e41abc9495611b9c9c67 100644 (file)
@@ -77,6 +77,8 @@ extern struct timespec xtime;
 extern struct timespec wall_to_monotonic;
 extern seqlock_t xtime_lock;
 
+void timekeeping_init(void);
+
 static inline unsigned long get_seconds(void)
 {
        return xtime.tv_sec;
index f715b9b897538cb04dc94fa900bd8c3f5d6e26e7..9a970d317ea509bd010cab1411c676c15c0f1907 100644 (file)
@@ -490,6 +490,7 @@ asmlinkage void __init start_kernel(void)
        hrtimers_init();
        softirq_init();
        time_init();
+       timekeeping_init();
 
        /*
         * HACK ALERT! This is early. We're enabling the console before
index f6ef00f4f90fb9069982c1ef6c986d8bb4e7e346..bc4b8a7161ff4e1898d9a9632c930b99fd450044 100644 (file)
@@ -10,6 +10,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o profile.o \
            kthread.o wait.o kfifo.o sys_ni.o posix-cpu-timers.o mutex.o \
            hrtimer.o
 
+obj-y += time/
 obj-$(CONFIG_DEBUG_MUTEXES) += mutex-debug.o
 obj-$(CONFIG_FUTEX) += futex.o
 ifeq ($(CONFIG_COMPAT),y)
index 95dd2200a1093d6a0a9e6796b6ed8cef616fe125..4288bfa12c3f03c2645b0fa9caf5747d0b982302 100644 (file)
@@ -56,7 +56,7 @@ static int finished_booting;
  *
  * Hack to avoid lots of clocksource churn at boot time
  */
-static int clocksource_done_booting(void)
+static int __init clocksource_done_booting(void)
 {
        finished_booting = 1;
        return 0;
@@ -289,7 +289,7 @@ static struct sys_device device_clocksource = {
        .cls    = &clocksource_sysclass,
 };
 
-static int init_clocksource_sysfs(void)
+static int __init init_clocksource_sysfs(void)
 {
        int error = sysdev_class_register(&clocksource_sysclass);
 
index eb97371b87d8fab6cef055b873a3ca4333c8656c..524c7f638365541d4e477706669dec4698ab6e62 100644 (file)
@@ -792,24 +792,93 @@ u64 current_tick_length(void)
        return ((u64) delta_nsec << (SHIFT_SCALE - 10)) + time_adj;
 }
 
+/* XXX - all of this timekeeping code should be later moved to time.c */
+#include <linux/clocksource.h>
+static struct clocksource *clock; /* pointer to current clocksource */
+static cycle_t last_clock_cycle;  /* cycle value at last update_wall_time */
 /*
- * Using a loop looks inefficient, but "ticks" is
- * usually just one (we shouldn't be losing ticks,
- * we're doing this this way mainly for interrupt
- * latency reasons, not because we think we'll
- * have lots of lost timer ticks
+ * timekeeping_init - Initializes the clocksource and common timekeeping values
  */
-static void update_wall_time(unsigned long ticks)
+void __init timekeeping_init(void)
 {
-       do {
-               ticks--;
+       unsigned long flags;
+
+       write_seqlock_irqsave(&xtime_lock, flags);
+       clock = get_next_clocksource();
+       calculate_clocksource_interval(clock, tick_nsec);
+       last_clock_cycle = read_clocksource(clock);
+       ntp_clear();
+       write_sequnlock_irqrestore(&xtime_lock, flags);
+}
+
+
+/*
+ * timekeeping_resume - Resumes the generic timekeeping subsystem.
+ * @dev:       unused
+ *
+ * This is for the generic clocksource timekeeping.
+ * xtime/wall_to_monotonic/jiffies/wall_jiffies/etc are
+ * still managed by arch specific suspend/resume code.
+ */
+static int timekeeping_resume(struct sys_device *dev)
+{
+       unsigned long flags;
+
+       write_seqlock_irqsave(&xtime_lock, flags);
+       /* restart the last cycle value */
+       last_clock_cycle = read_clocksource(clock);
+       write_sequnlock_irqrestore(&xtime_lock, flags);
+       return 0;
+}
+
+/* sysfs resume/suspend bits for timekeeping */
+static struct sysdev_class timekeeping_sysclass = {
+       .resume         = timekeeping_resume,
+       set_kset_name("timekeeping"),
+};
+
+static struct sys_device device_timer = {
+       .id             = 0,
+       .cls            = &timekeeping_sysclass,
+};
+
+static int __init timekeeping_init_device(void)
+{
+       int error = sysdev_class_register(&timekeeping_sysclass);
+       if (!error)
+               error = sysdev_register(&device_timer);
+       return error;
+}
+
+device_initcall(timekeeping_init_device);
+
+/*
+ * update_wall_time - Uses the current clocksource to increment the wall time
+ *
+ * Called from the timer interrupt, must hold a write on xtime_lock.
+ */
+static void update_wall_time(void)
+{
+       cycle_t now, offset;
+
+       now = read_clocksource(clock);
+       offset = (now - last_clock_cycle)&clock->mask;
+
+       /* normally this loop will run just once, however in the
+        * case of lost or late ticks, it will accumulate correctly.
+        */
+       while (offset > clock->interval_cycles) {
+               /* accumulate one interval */
+               last_clock_cycle += clock->interval_cycles;
+               offset -= clock->interval_cycles;
+
                update_wall_time_one_tick();
                if (xtime.tv_nsec >= 1000000000) {
                        xtime.tv_nsec -= 1000000000;
                        xtime.tv_sec++;
                        second_overflow();
                }
-       } while (ticks);
+       }
 }
 
 /*
@@ -915,10 +984,8 @@ static inline void update_times(void)
        unsigned long ticks;
 
        ticks = jiffies - wall_jiffies;
-       if (ticks) {
-               wall_jiffies += ticks;
-               update_wall_time(ticks);
-       }
+       wall_jiffies += ticks;
+       update_wall_time();
        calc_load(ticks);
 }