time.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:6k
源码类别:

嵌入式Linux

开发平台:

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