Merge ../linux-2.6-watchdog-mm
[linux-drm-fsl-dcu.git] / arch / s390 / kernel / time.c
1 /*
2  *  arch/s390/kernel/time.c
3  *    Time of day based timer functions.
4  *
5  *  S390 version
6  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
7  *    Author(s): Hartmut Penner (hp@de.ibm.com),
8  *               Martin Schwidefsky (schwidefsky@de.ibm.com),
9  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
10  *
11  *  Derived from "arch/i386/kernel/time.c"
12  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
13  */
14
15 #include <linux/errno.h>
16 #include <linux/module.h>
17 #include <linux/sched.h>
18 #include <linux/kernel.h>
19 #include <linux/param.h>
20 #include <linux/string.h>
21 #include <linux/mm.h>
22 #include <linux/interrupt.h>
23 #include <linux/time.h>
24 #include <linux/delay.h>
25 #include <linux/init.h>
26 #include <linux/smp.h>
27 #include <linux/types.h>
28 #include <linux/profile.h>
29 #include <linux/timex.h>
30 #include <linux/notifier.h>
31 #include <linux/clocksource.h>
32
33 #include <asm/uaccess.h>
34 #include <asm/delay.h>
35 #include <asm/s390_ext.h>
36 #include <asm/div64.h>
37 #include <asm/irq.h>
38 #include <asm/irq_regs.h>
39 #include <asm/timer.h>
40
41 /* change this if you have some constant time drift */
42 #define USECS_PER_JIFFY     ((unsigned long) 1000000/HZ)
43 #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
44
45 /*
46  * Create a small time difference between the timer interrupts
47  * on the different cpus to avoid lock contention.
48  */
49 #define CPU_DEVIATION       (smp_processor_id() << 12)
50
51 #define TICK_SIZE tick
52
53 static ext_int_info_t ext_int_info_cc;
54 static u64 init_timer_cc;
55 static u64 jiffies_timer_cc;
56 static u64 xtime_cc;
57
58 /*
59  * Scheduler clock - returns current time in nanosec units.
60  */
61 unsigned long long sched_clock(void)
62 {
63         return ((get_clock() - jiffies_timer_cc) * 125) >> 9;
64 }
65
66 /*
67  * Monotonic_clock - returns # of nanoseconds passed since time_init()
68  */
69 unsigned long long monotonic_clock(void)
70 {
71         return sched_clock();
72 }
73 EXPORT_SYMBOL(monotonic_clock);
74
75 void tod_to_timeval(__u64 todval, struct timespec *xtime)
76 {
77         unsigned long long sec;
78
79         sec = todval >> 12;
80         do_div(sec, 1000000);
81         xtime->tv_sec = sec;
82         todval -= (sec * 1000000) << 12;
83         xtime->tv_nsec = ((todval * 1000) >> 12);
84 }
85
86 #ifdef CONFIG_PROFILING
87 #define s390_do_profile()       profile_tick(CPU_PROFILING)
88 #else
89 #define s390_do_profile()       do { ; } while(0)
90 #endif /* CONFIG_PROFILING */
91
92
93 /*
94  * timer_interrupt() needs to keep up the real-time clock,
95  * as well as call the "do_timer()" routine every clocktick
96  */
97 void account_ticks(void)
98 {
99         __u64 tmp;
100         __u32 ticks;
101
102         /* Calculate how many ticks have passed. */
103         if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) {
104                 /*
105                  * We have to program the clock comparator even if
106                  * no tick has passed. That happens if e.g. an i/o
107                  * interrupt wakes up an idle processor that has
108                  * switched off its hz timer.
109                  */
110                 tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
111                 asm volatile ("SCKC %0" : : "m" (tmp));
112                 return;
113         }
114         tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer;
115         if (tmp >= 2*CLK_TICKS_PER_JIFFY) {  /* more than two ticks ? */
116                 ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1;
117                 S390_lowcore.jiffy_timer +=
118                         CLK_TICKS_PER_JIFFY * (__u64) ticks;
119         } else if (tmp >= CLK_TICKS_PER_JIFFY) {
120                 ticks = 2;
121                 S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY;
122         } else {
123                 ticks = 1;
124                 S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
125         }
126
127         /* set clock comparator for next tick */
128         tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION;
129         asm volatile ("SCKC %0" : : "m" (tmp));
130
131 #ifdef CONFIG_SMP
132         /*
133          * Do not rely on the boot cpu to do the calls to do_timer.
134          * Spread it over all cpus instead.
135          */
136         write_seqlock(&xtime_lock);
137         if (S390_lowcore.jiffy_timer > xtime_cc) {
138                 __u32 xticks;
139                 tmp = S390_lowcore.jiffy_timer - xtime_cc;
140                 if (tmp >= 2*CLK_TICKS_PER_JIFFY) {
141                         xticks = __div(tmp, CLK_TICKS_PER_JIFFY);
142                         xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY;
143                 } else {
144                         xticks = 1;
145                         xtime_cc += CLK_TICKS_PER_JIFFY;
146                 }
147                 do_timer(xticks);
148         }
149         write_sequnlock(&xtime_lock);
150 #else
151         do_timer(ticks);
152 #endif
153
154 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
155         account_tick_vtime(current);
156 #else
157         while (ticks--)
158                 update_process_times(user_mode(get_irq_regs()));
159 #endif
160
161         s390_do_profile();
162 }
163
164 #ifdef CONFIG_NO_IDLE_HZ
165
166 #ifdef CONFIG_NO_IDLE_HZ_INIT
167 int sysctl_hz_timer = 0;
168 #else
169 int sysctl_hz_timer = 1;
170 #endif
171
172 /*
173  * Stop the HZ tick on the current CPU.
174  * Only cpu_idle may call this function.
175  */
176 static inline void stop_hz_timer(void)
177 {
178         unsigned long flags;
179         unsigned long seq, next;
180         __u64 timer, todval;
181         int cpu = smp_processor_id();
182
183         if (sysctl_hz_timer != 0)
184                 return;
185
186         cpu_set(cpu, nohz_cpu_mask);
187
188         /*
189          * Leave the clock comparator set up for the next timer
190          * tick if either rcu or a softirq is pending.
191          */
192         if (rcu_needs_cpu(cpu) || local_softirq_pending()) {
193                 cpu_clear(cpu, nohz_cpu_mask);
194                 return;
195         }
196
197         /*
198          * This cpu is going really idle. Set up the clock comparator
199          * for the next event.
200          */
201         next = next_timer_interrupt();
202         do {
203                 seq = read_seqbegin_irqsave(&xtime_lock, flags);
204                 timer = ((__u64) next) - ((__u64) jiffies) + jiffies_64;
205         } while (read_seqretry_irqrestore(&xtime_lock, seq, flags));
206         todval = -1ULL;
207         /* Be careful about overflows. */
208         if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) {
209                 timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY;
210                 if (timer >= jiffies_timer_cc)
211                         todval = timer;
212         }
213         asm volatile ("SCKC %0" : : "m" (todval));
214 }
215
216 /*
217  * Start the HZ tick on the current CPU.
218  * Only cpu_idle may call this function.
219  */
220 static inline void start_hz_timer(void)
221 {
222         BUG_ON(!in_interrupt());
223
224         if (!cpu_isset(smp_processor_id(), nohz_cpu_mask))
225                 return;
226         account_ticks();
227         cpu_clear(smp_processor_id(), nohz_cpu_mask);
228 }
229
230 static int nohz_idle_notify(struct notifier_block *self,
231                             unsigned long action, void *hcpu)
232 {
233         switch (action) {
234         case CPU_IDLE:
235                 stop_hz_timer();
236                 break;
237         case CPU_NOT_IDLE:
238                 start_hz_timer();
239                 break;
240         }
241         return NOTIFY_OK;
242 }
243
244 static struct notifier_block nohz_idle_nb = {
245         .notifier_call = nohz_idle_notify,
246 };
247
248 void __init nohz_init(void)
249 {
250         if (register_idle_notifier(&nohz_idle_nb))
251                 panic("Couldn't register idle notifier");
252 }
253
254 #endif
255
256 /*
257  * Start the clock comparator on the current CPU.
258  */
259 void init_cpu_timer(void)
260 {
261         unsigned long cr0;
262         __u64 timer;
263
264         timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY;
265         S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY;
266         timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION;
267         asm volatile ("SCKC %0" : : "m" (timer));
268         /* allow clock comparator timer interrupt */
269         __ctl_store(cr0, 0, 0);
270         cr0 |= 0x800;
271         __ctl_load(cr0, 0, 0);
272 }
273
274 extern void vtime_init(void);
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
292 /*
293  * Initialize the TOD clock and the CPU timer of
294  * the boot cpu.
295  */
296 void __init time_init(void)
297 {
298         __u64 set_time_cc;
299         int cc;
300
301         /* kick the TOD clock */
302         asm volatile(
303                 "       stck    0(%2)\n"
304                 "       ipm     %0\n"
305                 "       srl     %0,28"
306                 : "=d" (cc), "=m" (init_timer_cc)
307                 : "a" (&init_timer_cc) : "cc");
308         switch (cc) {
309         case 0: /* clock in set state: all is fine */
310                 break;
311         case 1: /* clock in non-set state: FIXME */
312                 printk("time_init: TOD clock in non-set state\n");
313                 break;
314         case 2: /* clock in error state: FIXME */
315                 printk("time_init: TOD clock in error state\n");
316                 break;
317         case 3: /* clock in stopped or not-operational state: FIXME */
318                 printk("time_init: TOD clock stopped/non-operational\n");
319                 break;
320         }
321         jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY;
322
323         /* set xtime */
324         xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY;
325         set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
326                 (0x3c26700LL*1000000*4096);
327         tod_to_timeval(set_time_cc, &xtime);
328         set_normalized_timespec(&wall_to_monotonic,
329                                 -xtime.tv_sec, -xtime.tv_nsec);
330
331         /* request the clock comparator external interrupt */
332         if (register_early_external_interrupt(0x1004, NULL,
333                                               &ext_int_info_cc) != 0)
334                 panic("Couldn't request external interrupt 0x1004");
335
336         if (clocksource_register(&clocksource_tod) != 0)
337                 panic("Could not register TOD clock source");
338
339         init_cpu_timer();
340
341 #ifdef CONFIG_NO_IDLE_HZ
342         nohz_init();
343 #endif
344
345 #ifdef CONFIG_VIRT_TIMER
346         vtime_init();
347 #endif
348 }
349