diff options
Diffstat (limited to 'arch/s390/kernel/time.c')
-rw-r--r-- | arch/s390/kernel/time.c | 103 |
1 files changed, 29 insertions, 74 deletions
diff --git a/arch/s390/kernel/time.c b/arch/s390/kernel/time.c index 4bf66cc4a267..6cceed4df73e 100644 --- a/arch/s390/kernel/time.c +++ b/arch/s390/kernel/time.c | |||
@@ -28,12 +28,14 @@ | |||
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> |
34 | #include <asm/s390_ext.h> | 35 | #include <asm/s390_ext.h> |
35 | #include <asm/div64.h> | 36 | #include <asm/div64.h> |
36 | #include <asm/irq.h> | 37 | #include <asm/irq.h> |
38 | #include <asm/irq_regs.h> | ||
37 | #include <asm/timer.h> | 39 | #include <asm/timer.h> |
38 | 40 | ||
39 | /* change this if you have some constant time drift */ | 41 | /* change this if you have some constant time drift */ |
@@ -81,78 +83,10 @@ void tod_to_timeval(__u64 todval, struct timespec *xtime) | |||
81 | xtime->tv_nsec = ((todval * 1000) >> 12); | 83 | xtime->tv_nsec = ((todval * 1000) >> 12); |
82 | } | 84 | } |
83 | 85 | ||
84 | static inline unsigned long do_gettimeoffset(void) | ||
85 | { | ||
86 | __u64 now; | ||
87 | |||
88 | now = (get_clock() - jiffies_timer_cc) >> 12; | ||
89 | now -= (__u64) jiffies * USECS_PER_JIFFY; | ||
90 | return (unsigned long) now; | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | * This version of gettimeofday has microsecond resolution. | ||
95 | */ | ||
96 | void do_gettimeofday(struct timeval *tv) | ||
97 | { | ||
98 | unsigned long flags; | ||
99 | unsigned long seq; | ||
100 | unsigned long usec, sec; | ||
101 | |||
102 | do { | ||
103 | seq = read_seqbegin_irqsave(&xtime_lock, flags); | ||
104 | |||
105 | sec = xtime.tv_sec; | ||
106 | usec = xtime.tv_nsec / 1000 + do_gettimeoffset(); | ||
107 | } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); | ||
108 | |||
109 | while (usec >= 1000000) { | ||
110 | usec -= 1000000; | ||
111 | sec++; | ||
112 | } | ||
113 | |||
114 | tv->tv_sec = sec; | ||
115 | tv->tv_usec = usec; | ||
116 | } | ||
117 | |||
118 | EXPORT_SYMBOL(do_gettimeofday); | ||
119 | |||
120 | int do_settimeofday(struct timespec *tv) | ||
121 | { | ||
122 | time_t wtm_sec, sec = tv->tv_sec; | ||
123 | long wtm_nsec, nsec = tv->tv_nsec; | ||
124 | |||
125 | if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) | ||
126 | return -EINVAL; | ||
127 | |||
128 | write_seqlock_irq(&xtime_lock); | ||
129 | /* This is revolting. We need to set the xtime.tv_nsec | ||
130 | * correctly. However, the value in this location is | ||
131 | * is value at the last tick. | ||
132 | * Discover what correction gettimeofday | ||
133 | * would have done, and then undo it! | ||
134 | */ | ||
135 | nsec -= do_gettimeoffset() * 1000; | ||
136 | |||
137 | wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); | ||
138 | wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); | ||
139 | |||
140 | set_normalized_timespec(&xtime, sec, nsec); | ||
141 | set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); | ||
142 | |||
143 | ntp_clear(); | ||
144 | write_sequnlock_irq(&xtime_lock); | ||
145 | clock_was_set(); | ||
146 | return 0; | ||
147 | } | ||
148 | |||
149 | EXPORT_SYMBOL(do_settimeofday); | ||
150 | |||
151 | |||
152 | #ifdef CONFIG_PROFILING | 86 | #ifdef CONFIG_PROFILING |
153 | #define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs) | 87 | #define s390_do_profile() profile_tick(CPU_PROFILING) |
154 | #else | 88 | #else |
155 | #define s390_do_profile(regs) do { ; } while(0) | 89 | #define s390_do_profile() do { ; } while(0) |
156 | #endif /* CONFIG_PROFILING */ | 90 | #endif /* CONFIG_PROFILING */ |
157 | 91 | ||
158 | 92 | ||
@@ -160,7 +94,7 @@ EXPORT_SYMBOL(do_settimeofday); | |||
160 | * timer_interrupt() needs to keep up the real-time clock, | 94 | * timer_interrupt() needs to keep up the real-time clock, |
161 | * as well as call the "do_timer()" routine every clocktick | 95 | * as well as call the "do_timer()" routine every clocktick |
162 | */ | 96 | */ |
163 | void account_ticks(struct pt_regs *regs) | 97 | void account_ticks(void) |
164 | { | 98 | { |
165 | __u64 tmp; | 99 | __u64 tmp; |
166 | __u32 ticks; | 100 | __u32 ticks; |
@@ -221,10 +155,10 @@ void account_ticks(struct pt_regs *regs) | |||
221 | account_tick_vtime(current); | 155 | account_tick_vtime(current); |
222 | #else | 156 | #else |
223 | while (ticks--) | 157 | while (ticks--) |
224 | update_process_times(user_mode(regs)); | 158 | update_process_times(user_mode(get_irq_regs())); |
225 | #endif | 159 | #endif |
226 | 160 | ||
227 | s390_do_profile(regs); | 161 | s390_do_profile(); |
228 | } | 162 | } |
229 | 163 | ||
230 | #ifdef CONFIG_NO_IDLE_HZ | 164 | #ifdef CONFIG_NO_IDLE_HZ |
@@ -285,9 +219,11 @@ static inline void stop_hz_timer(void) | |||
285 | */ | 219 | */ |
286 | static inline void start_hz_timer(void) | 220 | static inline void start_hz_timer(void) |
287 | { | 221 | { |
222 | BUG_ON(!in_interrupt()); | ||
223 | |||
288 | if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) | 224 | if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) |
289 | return; | 225 | return; |
290 | account_ticks(task_pt_regs(current)); | 226 | account_ticks(); |
291 | cpu_clear(smp_processor_id(), nohz_cpu_mask); | 227 | cpu_clear(smp_processor_id(), nohz_cpu_mask); |
292 | } | 228 | } |
293 | 229 | ||
@@ -337,6 +273,22 @@ void init_cpu_timer(void) | |||
337 | 273 | ||
338 | extern void vtime_init(void); | 274 | extern void vtime_init(void); |
339 | 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 | |||
340 | /* | 292 | /* |
341 | * Initialize the TOD clock and the CPU timer of | 293 | * Initialize the TOD clock and the CPU timer of |
342 | * the boot cpu. | 294 | * the boot cpu. |
@@ -381,6 +333,9 @@ void __init time_init(void) | |||
381 | &ext_int_info_cc) != 0) | 333 | &ext_int_info_cc) != 0) |
382 | panic("Couldn't request external interrupt 0x1004"); | 334 | panic("Couldn't request external interrupt 0x1004"); |
383 | 335 | ||
336 | if (clocksource_register(&clocksource_tod) != 0) | ||
337 | panic("Could not register TOD clock source"); | ||
338 | |||
384 | init_cpu_timer(); | 339 | init_cpu_timer(); |
385 | 340 | ||
386 | #ifdef CONFIG_NO_IDLE_HZ | 341 | #ifdef CONFIG_NO_IDLE_HZ |