|
@@ -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);
|
|
|
}
|
|
|
|