time.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:6k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  arch/s390/kernel/time.c
  3.  *
  4.  *  S390 version
  5.  *    Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
  6.  *    Author(s): Hartmut Penner (hp@de.ibm.com),
  7.  *               Martin Schwidefsky (schwidefsky@de.ibm.com),
  8.  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
  9.  *
  10.  *  Derived from "arch/i386/kernel/time.c"
  11.  *    Copyright (C) 1991, 1992, 1995  Linus Torvalds
  12.  */
  13. #include <linux/errno.h>
  14. #include <linux/sched.h>
  15. #include <linux/kernel.h>
  16. #include <linux/param.h>
  17. #include <linux/string.h>
  18. #include <linux/mm.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/time.h>
  21. #include <linux/delay.h>
  22. #include <linux/init.h>
  23. #include <linux/smp.h>
  24. #include <linux/types.h>
  25. #include <asm/uaccess.h>
  26. #include <asm/delay.h>
  27. #include <asm/s390_ext.h>
  28. #include <linux/timex.h>
  29. #include <linux/config.h>
  30. #include <asm/irq.h>
  31. /* change this if you have some constant time drift */
  32. #define USECS_PER_JIFFY     ((unsigned long) 1000000/HZ)
  33. #define CLK_TICKS_PER_JIFFY ((unsigned long) USECS_PER_JIFFY << 12)
  34. #define TICK_SIZE tick
  35. static ext_int_info_t ext_int_info_timer;
  36. static uint64_t init_timer_cc;
  37. extern rwlock_t xtime_lock;
  38. extern unsigned long wall_jiffies;
  39. void tod_to_timeval(__u64 todval, struct timeval *xtime)
  40. {
  41.         const int high_bit = 0x80000000L;
  42.         const int c_f4240 = 0xf4240L;
  43.         const int c_7a120 = 0x7a120;
  44. /* We have to divide the 64 bit value todval by 4096
  45.  * (because the 2^12 bit is the one that changes every 
  46.          * microsecond) and then split it into seconds and
  47.          * microseconds. A value of max (2^52-1) divided by
  48.          * the value 0xF4240 can yield a max result of approx
  49.          * (2^32.068). Thats to big to fit into a signed int
  50.  *   ... hacking time!
  51.          */
  52. asm volatile ("L     2,%1nt"
  53.       "LR    3,2nt"
  54.       "SRL   2,12nt"
  55.       "SLL   3,20nt"
  56.       "L     4,%O1+4(%R1)nt"
  57.       "SRL   4,12nt"
  58.       "OR    3,4nt"  /* now R2/R3 contain (todval >> 12) */
  59.       "SR    4,4nt"
  60.       "CL    2,%2nt"
  61.       "JL    .+12nt"
  62.       "S     2,%2nt"
  63.       "L     4,%3nt"
  64.                       "D     2,%4nt"
  65.       "OR    3,4nt"
  66.       "ST    2,%O0+4(%R0)nt"
  67.       "ST    3,%0"
  68.       : "=m" (*xtime) : "m" (todval),
  69.         "m" (c_7a120), "m" (high_bit), "m" (c_f4240)
  70.       : "cc", "memory", "2", "3", "4" );
  71. }
  72. static inline unsigned long do_gettimeoffset(void) 
  73. {
  74. __u64 now;
  75. asm ("STCK 0(%0)" : : "a" (&now) : "memory", "cc");
  76.         now = (now - init_timer_cc) >> 12;
  77. /* We require the offset from the latest update of xtime */
  78. now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
  79. return (unsigned long) now;
  80. }
  81. /*
  82.  * This version of gettimeofday has microsecond resolution.
  83.  */
  84. void do_gettimeofday(struct timeval *tv)
  85. {
  86. unsigned long flags;
  87. unsigned long usec, sec;
  88. read_lock_irqsave(&xtime_lock, flags);
  89. sec = xtime.tv_sec;
  90. usec = xtime.tv_usec + do_gettimeoffset();
  91. read_unlock_irqrestore(&xtime_lock, flags);
  92. while (usec >= 1000000) {
  93. usec -= 1000000;
  94. sec++;
  95. }
  96. tv->tv_sec = sec;
  97. tv->tv_usec = usec;
  98. }
  99. void do_settimeofday(struct timeval *tv)
  100. {
  101. write_lock_irq(&xtime_lock);
  102. /* This is revolting. We need to set the xtime.tv_usec
  103.  * correctly. However, the value in this location is
  104.  * is value at the last tick.
  105.  * Discover what correction gettimeofday
  106.  * would have done, and then undo it!
  107.  */
  108. tv->tv_usec -= do_gettimeoffset();
  109. while (tv->tv_usec < 0) {
  110. tv->tv_usec += 1000000;
  111. tv->tv_sec--;
  112. }
  113. xtime = *tv;
  114. time_adjust = 0; /* stop active adjtime() */
  115. time_status |= STA_UNSYNC;
  116. time_maxerror = NTP_PHASE_LIMIT;
  117. time_esterror = NTP_PHASE_LIMIT;
  118. write_unlock_irq(&xtime_lock);
  119. }
  120. /*
  121.  * timer_interrupt() needs to keep up the real-time clock,
  122.  * as well as call the "do_timer()" routine every clocktick
  123.  */
  124. #ifdef CONFIG_SMP
  125. extern __u16 boot_cpu_addr;
  126. #endif
  127. static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
  128. {
  129. int cpu = smp_processor_id();
  130. irq_enter(cpu, 0);
  131. /*
  132.  * set clock comparator for next tick
  133.  */
  134.         S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
  135.         asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
  136. #ifdef CONFIG_SMP
  137. if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr)
  138. write_lock(&xtime_lock);
  139. update_process_times(user_mode(regs));
  140. if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) {
  141. do_timer(regs);
  142. write_unlock(&xtime_lock);
  143. }
  144. #else
  145. do_timer(regs);
  146. #endif
  147. irq_exit(cpu, 0);
  148. }
  149. /*
  150.  * Start the clock comparator on the current CPU
  151.  */
  152. void init_cpu_timer(void)
  153. {
  154. unsigned long cr0;
  155.         /* allow clock comparator timer interrupt */
  156.         asm volatile ("STCTL 0,0,%0" : "=m" (cr0) : : "memory");
  157.         cr0 |= 0x800;
  158.         asm volatile ("LCTL 0,0,%0" : : "m" (cr0) : "memory");
  159. S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
  160. S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
  161. asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
  162. }
  163. /*
  164.  * Initialize the TOD clock and the CPU timer of
  165.  * the boot cpu.
  166.  */
  167. void __init time_init(void)
  168. {
  169.         __u64 set_time_cc;
  170. int cc;
  171.         /* kick the TOD clock */
  172.         asm volatile ("STCK 0(%1)nt"
  173.                       "IPM  %0nt"
  174.                       "SRL  %0,28" : "=r" (cc) : "a" (&init_timer_cc) 
  175.    : "memory", "cc");
  176.         switch (cc) {
  177.         case 0: /* clock in set state: all is fine */
  178.                 break;
  179.         case 1: /* clock in non-set state: FIXME */
  180.                 printk("time_init: TOD clock in non-set staten");
  181.                 break;
  182.         case 2: /* clock in error state: FIXME */
  183.                 printk("time_init: TOD clock in error staten");
  184.                 break;
  185.         case 3: /* clock in stopped or not-operational state: FIXME */
  186.                 printk("time_init: TOD clock stopped/non-operationaln");
  187.                 break;
  188.         }
  189. /* set xtime */
  190.         set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
  191.                       (0x3c26700LL*1000000*4096);
  192.         tod_to_timeval(set_time_cc, &xtime);
  193.         /* request the 0x1004 external interrupt */
  194.         if (register_early_external_interrupt(0x1004, do_comparator_interrupt,
  195.       &ext_int_info_timer) != 0)
  196.                 panic("Couldn't request external interrupt 0x1004");
  197.         /* init CPU timer */
  198.         init_cpu_timer();
  199. }