time.c 8.3 KB

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