aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390/kernel/time.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/s390/kernel/time.c')
-rw-r--r--arch/s390/kernel/time.c88
1 files changed, 20 insertions, 68 deletions
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c
index 2c8c690688cb..6cceed4df73e 100644
--- a/arch/s390/kernel/time.c
+++ b/arch/s390/kernel/time.c
@@ -28,6 +28,7 @@
28#include <linux/profile.h> 28#include <linux/profile.h>
29#include <linux/timex.h> 29#include <linux/timex.h>
30#include <linux/notifier.h> 30#include <linux/notifier.h>
31#include <linux/clocksource.h>
31 32
32#include <asm/uaccess.h> 33#include <asm/uaccess.h>
33#include <asm/delay.h> 34#include <asm/delay.h>
@@ -82,74 +83,6 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime)
82 xtime->tv_nsec = ((todval * 1000) >> 12); 83 xtime->tv_nsec = ((todval * 1000) >> 12);
83} 84}
84 85
85static inline unsigned long do_gettimeoffset(void)
86{
87 __u64 now;
88
89 now = (get_clock() - jiffies_timer_cc) >> 12;
90 now -= (__u64) jiffies * USECS_PER_JIFFY;
91 return (unsigned long) now;
92}
93
94/*
95 * This version of gettimeofday has microsecond resolution.
96 */
97void do_gettimeofday(struct timeval *tv)
98{
99 unsigned long flags;
100 unsigned long seq;
101 unsigned long usec, sec;
102
103 do {
104 seq = read_seqbegin_irqsave(&xtime_lock, flags);
105
106 sec = xtime.tv_sec;
107 usec = xtime.tv_nsec / 1000 + do_gettimeoffset();
108 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
109
110 while (usec >= 1000000) {
111 usec -= 1000000;
112 sec++;
113 }
114
115 tv->tv_sec = sec;
116 tv->tv_usec = usec;
117}
118
119EXPORT_SYMBOL(do_gettimeofday);
120
121int do_settimeofday(struct timespec *tv)
122{
123 time_t wtm_sec, sec = tv->tv_sec;
124 long wtm_nsec, nsec = tv->tv_nsec;
125
126 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC)
127 return -EINVAL;
128
129 write_seqlock_irq(&xtime_lock);
130 /* This is revolting. We need to set the xtime.tv_nsec
131 * correctly. However, the value in this location is
132 * is value at the last tick.
133 * Discover what correction gettimeofday
134 * would have done, and then undo it!
135 */
136 nsec -= do_gettimeoffset() * 1000;
137
138 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec);
139 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec);
140
141 set_normalized_timespec(&xtime, sec, nsec);
142 set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec);
143
144 ntp_clear();
145 write_sequnlock_irq(&xtime_lock);
146 clock_was_set();
147 return 0;
148}
149
150EXPORT_SYMBOL(do_settimeofday);
151
152
153#ifdef CONFIG_PROFILING 86#ifdef CONFIG_PROFILING
154#define s390_do_profile() profile_tick(CPU_PROFILING) 87#define s390_do_profile() profile_tick(CPU_PROFILING)
155#else 88#else
@@ -340,6 +273,22 @@ void init_cpu_timer(void)
340 273
341extern void vtime_init(void); 274extern void vtime_init(void);
342 275
276static cycle_t read_tod_clock(void)
277{
278 return get_clock();
279}
280
281static struct clocksource clocksource_tod = {
282 .name = "tod",
283 .rating = 100,
284 .read = read_tod_clock,
285 .mask = -1ULL,
286 .mult = 1000,
287 .shift = 12,
288 .is_continuous = 1,
289};
290
291
343/* 292/*
344 * Initialize the TOD clock and the CPU timer of 293 * Initialize the TOD clock and the CPU timer of
345 * the boot cpu. 294 * the boot cpu.
@@ -384,6 +333,9 @@ void __init time_init(void)
384 &ext_int_info_cc) != 0) 333 &ext_int_info_cc) != 0)
385 panic("Couldn't request external interrupt 0x1004"); 334 panic("Couldn't request external interrupt 0x1004");
386 335
336 if (clocksource_register(&clocksource_tod) != 0)
337 panic("Could not register TOD clock source");
338
387 init_cpu_timer(); 339 init_cpu_timer();
388 340
389#ifdef CONFIG_NO_IDLE_HZ 341#ifdef CONFIG_NO_IDLE_HZ