diff options
-rw-r--r-- | arch/s390/Kconfig | 3 | ||||
-rw-r--r-- | arch/s390/defconfig | 1 | ||||
-rw-r--r-- | arch/s390/kernel/time.c | 88 |
3 files changed, 24 insertions, 68 deletions
diff --git a/arch/s390/Kconfig b/arch/s390/Kconfig index 51c2dfe89c62..608193cfe43f 100644 --- a/arch/s390/Kconfig +++ b/arch/s390/Kconfig | |||
@@ -30,6 +30,9 @@ config GENERIC_CALIBRATE_DELAY | |||
30 | bool | 30 | bool |
31 | default y | 31 | default y |
32 | 32 | ||
33 | config GENERIC_TIME | ||
34 | def_bool y | ||
35 | |||
33 | config GENERIC_BUST_SPINLOCK | 36 | config GENERIC_BUST_SPINLOCK |
34 | bool | 37 | bool |
35 | 38 | ||
diff --git a/arch/s390/defconfig b/arch/s390/defconfig index b6cad75fd1f4..a3257398ea8d 100644 --- a/arch/s390/defconfig +++ b/arch/s390/defconfig | |||
@@ -9,6 +9,7 @@ CONFIG_STACKTRACE_SUPPORT=y | |||
9 | CONFIG_RWSEM_XCHGADD_ALGORITHM=y | 9 | CONFIG_RWSEM_XCHGADD_ALGORITHM=y |
10 | CONFIG_GENERIC_HWEIGHT=y | 10 | CONFIG_GENERIC_HWEIGHT=y |
11 | CONFIG_GENERIC_CALIBRATE_DELAY=y | 11 | CONFIG_GENERIC_CALIBRATE_DELAY=y |
12 | CONFIG_GENERIC_TIME=y | ||
12 | CONFIG_S390=y | 13 | CONFIG_S390=y |
13 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" | 14 | CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config" |
14 | 15 | ||
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 | ||
85 | static 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 | */ | ||
97 | void 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 | |||
119 | EXPORT_SYMBOL(do_gettimeofday); | ||
120 | |||
121 | int 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 | |||
150 | EXPORT_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 | ||
341 | extern void vtime_init(void); | 274 | extern void vtime_init(void); |
342 | 275 | ||
276 | static cycle_t read_tod_clock(void) | ||
277 | { | ||
278 | return get_clock(); | ||
279 | } | ||
280 | |||
281 | static 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 |