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/config.h> 16 #include <linux/errno.h> 17 #include <linux/module.h> 18 #include <linux/sched.h> 19 #include <linux/kernel.h> 20 #include <linux/param.h> 21 #include <linux/string.h> 22 #include <linux/mm.h> 23 #include <linux/interrupt.h> 24 #include <linux/time.h> 25 #include <linux/delay.h> 26 #include <linux/init.h> 27 #include <linux/smp.h> 28 #include <linux/types.h> 29 #include <linux/profile.h> 30 #include <linux/timex.h> 31 #include <linux/notifier.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/timer.h> 39 40 /* change this if you have some constant time drift */ 41 #define USECS_PER_JIFFY ((unsigned long) 1000000/HZ) 42 #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12) 43 44 /* 45 * Create a small time difference between the timer interrupts 46 * on the different cpus to avoid lock contention. 47 */ 48 #define CPU_DEVIATION (smp_processor_id() << 12) 49 50 #define TICK_SIZE tick 51 52 u64 jiffies_64 = INITIAL_JIFFIES; 53 54 EXPORT_SYMBOL(jiffies_64); 55 56 static ext_int_info_t ext_int_info_cc; 57 static u64 init_timer_cc; 58 static u64 jiffies_timer_cc; 59 static u64 xtime_cc; 60 61 extern unsigned long wall_jiffies; 62 63 /* 64 * Scheduler clock - returns current time in nanosec units. 65 */ 66 unsigned long long sched_clock(void) 67 { 68 return ((get_clock() - jiffies_timer_cc) * 1000) >> 12; 69 } 70 71 void tod_to_timeval(__u64 todval, struct timespec *xtime) 72 { 73 unsigned long long sec; 74 75 sec = todval >> 12; 76 do_div(sec, 1000000); 77 xtime->tv_sec = sec; 78 todval -= (sec * 1000000) << 12; 79 xtime->tv_nsec = ((todval * 1000) >> 12); 80 } 81 82 static inline unsigned long do_gettimeoffset(void) 83 { 84 __u64 now; 85 86 now = (get_clock() - jiffies_timer_cc) >> 12; 87 /* We require the offset from the latest update of xtime */ 88 now -= (__u64) wall_jiffies*USECS_PER_JIFFY; 89 return (unsigned long) now; 90 } 91 92 /* 93 * This version of gettimeofday has microsecond resolution. 94 */ 95 void do_gettimeofday(struct timeval *tv) 96 { 97 unsigned long flags; 98 unsigned long seq; 99 unsigned long usec, sec; 100 101 do { 102 seq = read_seqbegin_irqsave(&xtime_lock, flags); 103 104 sec = xtime.tv_sec; 105 usec = xtime.tv_nsec / 1000 + do_gettimeoffset(); 106 } while (read_seqretry_irqrestore(&xtime_lock, seq, flags)); 107 108 while (usec >= 1000000) { 109 usec -= 1000000; 110 sec++; 111 } 112 113 tv->tv_sec = sec; 114 tv->tv_usec = usec; 115 } 116 117 EXPORT_SYMBOL(do_gettimeofday); 118 119 int do_settimeofday(struct timespec *tv) 120 { 121 time_t wtm_sec, sec = tv->tv_sec; 122 long wtm_nsec, nsec = tv->tv_nsec; 123 124 if ((unsigned long)tv->tv_nsec >= NSEC_PER_SEC) 125 return -EINVAL; 126 127 write_seqlock_irq(&xtime_lock); 128 /* This is revolting. We need to set the xtime.tv_nsec 129 * correctly. However, the value in this location is 130 * is value at the last tick. 131 * Discover what correction gettimeofday 132 * would have done, and then undo it! 133 */ 134 nsec -= do_gettimeoffset() * 1000; 135 136 wtm_sec = wall_to_monotonic.tv_sec + (xtime.tv_sec - sec); 137 wtm_nsec = wall_to_monotonic.tv_nsec + (xtime.tv_nsec - nsec); 138 139 set_normalized_timespec(&xtime, sec, nsec); 140 set_normalized_timespec(&wall_to_monotonic, wtm_sec, wtm_nsec); 141 142 ntp_clear(); 143 write_sequnlock_irq(&xtime_lock); 144 clock_was_set(); 145 return 0; 146 } 147 148 EXPORT_SYMBOL(do_settimeofday); 149 150 151 #ifdef CONFIG_PROFILING 152 #define s390_do_profile(regs) profile_tick(CPU_PROFILING, regs) 153 #else 154 #define s390_do_profile(regs) do { ; } while(0) 155 #endif /* CONFIG_PROFILING */ 156 157 158 /* 159 * timer_interrupt() needs to keep up the real-time clock, 160 * as well as call the "do_timer()" routine every clocktick 161 */ 162 void account_ticks(struct pt_regs *regs) 163 { 164 __u64 tmp; 165 __u32 ticks, xticks; 166 167 /* Calculate how many ticks have passed. */ 168 if (S390_lowcore.int_clock < S390_lowcore.jiffy_timer) { 169 /* 170 * We have to program the clock comparator even if 171 * no tick has passed. That happens if e.g. an i/o 172 * interrupt wakes up an idle processor that has 173 * switched off its hz timer. 174 */ 175 tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; 176 asm volatile ("SCKC %0" : : "m" (tmp)); 177 return; 178 } 179 tmp = S390_lowcore.int_clock - S390_lowcore.jiffy_timer; 180 if (tmp >= 2*CLK_TICKS_PER_JIFFY) { /* more than two ticks ? */ 181 ticks = __div(tmp, CLK_TICKS_PER_JIFFY) + 1; 182 S390_lowcore.jiffy_timer += 183 CLK_TICKS_PER_JIFFY * (__u64) ticks; 184 } else if (tmp >= CLK_TICKS_PER_JIFFY) { 185 ticks = 2; 186 S390_lowcore.jiffy_timer += 2*CLK_TICKS_PER_JIFFY; 187 } else { 188 ticks = 1; 189 S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY; 190 } 191 192 /* set clock comparator for next tick */ 193 tmp = S390_lowcore.jiffy_timer + CPU_DEVIATION; 194 asm volatile ("SCKC %0" : : "m" (tmp)); 195 196 #ifdef CONFIG_SMP 197 /* 198 * Do not rely on the boot cpu to do the calls to do_timer. 199 * Spread it over all cpus instead. 200 */ 201 write_seqlock(&xtime_lock); 202 if (S390_lowcore.jiffy_timer > xtime_cc) { 203 tmp = S390_lowcore.jiffy_timer - xtime_cc; 204 if (tmp >= 2*CLK_TICKS_PER_JIFFY) { 205 xticks = __div(tmp, CLK_TICKS_PER_JIFFY); 206 xtime_cc += (__u64) xticks * CLK_TICKS_PER_JIFFY; 207 } else { 208 xticks = 1; 209 xtime_cc += CLK_TICKS_PER_JIFFY; 210 } 211 while (xticks--) 212 do_timer(regs); 213 } 214 write_sequnlock(&xtime_lock); 215 #else 216 for (xticks = ticks; xticks > 0; xticks--) 217 do_timer(regs); 218 #endif 219 220 #ifdef CONFIG_VIRT_CPU_ACCOUNTING 221 account_user_vtime(current); 222 #else 223 while (ticks--) 224 update_process_times(user_mode(regs)); 225 #endif 226 227 s390_do_profile(regs); 228 } 229 230 #ifdef CONFIG_NO_IDLE_HZ 231 232 #ifdef CONFIG_NO_IDLE_HZ_INIT 233 int sysctl_hz_timer = 0; 234 #else 235 int sysctl_hz_timer = 1; 236 #endif 237 238 /* 239 * Stop the HZ tick on the current CPU. 240 * Only cpu_idle may call this function. 241 */ 242 static inline void stop_hz_timer(void) 243 { 244 __u64 timer, todval; 245 246 if (sysctl_hz_timer != 0) 247 return; 248 249 cpu_set(smp_processor_id(), nohz_cpu_mask); 250 251 /* 252 * Leave the clock comparator set up for the next timer 253 * tick if either rcu or a softirq is pending. 254 */ 255 if (rcu_pending(smp_processor_id()) || local_softirq_pending()) { 256 cpu_clear(smp_processor_id(), nohz_cpu_mask); 257 return; 258 } 259 260 /* 261 * This cpu is going really idle. Set up the clock comparator 262 * for the next event. 263 */ 264 timer = (__u64) (next_timer_interrupt() - jiffies) + jiffies_64; 265 todval = -1ULL; 266 /* Be careful about overflows. */ 267 if (timer < (-1ULL / CLK_TICKS_PER_JIFFY)) { 268 timer = jiffies_timer_cc + timer * CLK_TICKS_PER_JIFFY; 269 if (timer >= jiffies_timer_cc) 270 todval = timer; 271 } 272 asm volatile ("SCKC %0" : : "m" (todval)); 273 } 274 275 /* 276 * Start the HZ tick on the current CPU. 277 * Only cpu_idle may call this function. 278 */ 279 static inline void start_hz_timer(void) 280 { 281 if (!cpu_isset(smp_processor_id(), nohz_cpu_mask)) 282 return; 283 account_ticks(__KSTK_PTREGS(current)); 284 cpu_clear(smp_processor_id(), nohz_cpu_mask); 285 } 286 287 static int nohz_idle_notify(struct notifier_block *self, 288 unsigned long action, void *hcpu) 289 { 290 switch (action) { 291 case CPU_IDLE: 292 stop_hz_timer(); 293 break; 294 case CPU_NOT_IDLE: 295 start_hz_timer(); 296 break; 297 } 298 return NOTIFY_OK; 299 } 300 301 static struct notifier_block nohz_idle_nb = { 302 .notifier_call = nohz_idle_notify, 303 }; 304 305 void __init nohz_init(void) 306 { 307 if (register_idle_notifier(&nohz_idle_nb)) 308 panic("Couldn't register idle notifier"); 309 } 310 311 #endif 312 313 /* 314 * Start the clock comparator on the current CPU. 315 */ 316 void init_cpu_timer(void) 317 { 318 unsigned long cr0; 319 __u64 timer; 320 321 timer = jiffies_timer_cc + jiffies_64 * CLK_TICKS_PER_JIFFY; 322 S390_lowcore.jiffy_timer = timer + CLK_TICKS_PER_JIFFY; 323 timer += CLK_TICKS_PER_JIFFY + CPU_DEVIATION; 324 asm volatile ("SCKC %0" : : "m" (timer)); 325 /* allow clock comparator timer interrupt */ 326 __ctl_store(cr0, 0, 0); 327 cr0 |= 0x800; 328 __ctl_load(cr0, 0, 0); 329 } 330 331 extern void vtime_init(void); 332 333 /* 334 * Initialize the TOD clock and the CPU timer of 335 * the boot cpu. 336 */ 337 void __init time_init(void) 338 { 339 __u64 set_time_cc; 340 int cc; 341 342 /* kick the TOD clock */ 343 asm volatile ("STCK 0(%1)\n\t" 344 "IPM %0\n\t" 345 "SRL %0,28" : "=r" (cc) : "a" (&init_timer_cc) 346 : "memory", "cc"); 347 switch (cc) { 348 case 0: /* clock in set state: all is fine */ 349 break; 350 case 1: /* clock in non-set state: FIXME */ 351 printk("time_init: TOD clock in non-set state\n"); 352 break; 353 case 2: /* clock in error state: FIXME */ 354 printk("time_init: TOD clock in error state\n"); 355 break; 356 case 3: /* clock in stopped or not-operational state: FIXME */ 357 printk("time_init: TOD clock stopped/non-operational\n"); 358 break; 359 } 360 jiffies_timer_cc = init_timer_cc - jiffies_64 * CLK_TICKS_PER_JIFFY; 361 362 /* set xtime */ 363 xtime_cc = init_timer_cc + CLK_TICKS_PER_JIFFY; 364 set_time_cc = init_timer_cc - 0x8126d60e46000000LL + 365 (0x3c26700LL*1000000*4096); 366 tod_to_timeval(set_time_cc, &xtime); 367 set_normalized_timespec(&wall_to_monotonic, 368 -xtime.tv_sec, -xtime.tv_nsec); 369 370 /* request the clock comparator external interrupt */ 371 if (register_early_external_interrupt(0x1004, 0, 372 &ext_int_info_cc) != 0) 373 panic("Couldn't request external interrupt 0x1004"); 374 375 init_cpu_timer(); 376 377 #ifdef CONFIG_NO_IDLE_HZ 378 nohz_init(); 379 #endif 380 381 #ifdef CONFIG_VIRT_TIMER 382 vtime_init(); 383 #endif 384 } 385 386