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

嵌入式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 <linux/timex.h>
  28. #include <linux/config.h>
  29. #include <asm/irq.h>
  30. #include <asm/s390_ext.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.         todval >>= 12;
  41.         xtime->tv_sec = todval / 1000000;
  42.         xtime->tv_usec = todval % 1000000;
  43. }
  44. static inline unsigned long do_gettimeoffset(void) 
  45. {
  46. __u64 now;
  47. asm ("STCK %0" : "=m" (now));
  48.         now = (now - init_timer_cc) >> 12;
  49. /* We require the offset from the latest update of xtime */
  50. now -= (__u64) wall_jiffies*USECS_PER_JIFFY;
  51. return (unsigned long) now;
  52. }
  53. /*
  54.  * This version of gettimeofday has microsecond resolution.
  55.  */
  56. void do_gettimeofday(struct timeval *tv)
  57. {
  58. unsigned long flags;
  59. unsigned long usec, sec;
  60. read_lock_irqsave(&xtime_lock, flags);
  61. sec = xtime.tv_sec;
  62. usec = xtime.tv_usec + do_gettimeoffset();
  63. read_unlock_irqrestore(&xtime_lock, flags);
  64. while (usec >= 1000000) {
  65. usec -= 1000000;
  66. sec++;
  67. }
  68. tv->tv_sec = sec;
  69. tv->tv_usec = usec;
  70. }
  71. void do_settimeofday(struct timeval *tv)
  72. {
  73. write_lock_irq(&xtime_lock);
  74. /* This is revolting. We need to set the xtime.tv_usec
  75.  * correctly. However, the value in this location is
  76.  * is value at the last tick.
  77.  * Discover what correction gettimeofday
  78.  * would have done, and then undo it!
  79.  */
  80. tv->tv_usec -= do_gettimeoffset();
  81. while (tv->tv_usec < 0) {
  82. tv->tv_usec += 1000000;
  83. tv->tv_sec--;
  84. }
  85. xtime = *tv;
  86. time_adjust = 0; /* stop active adjtime() */
  87. time_status |= STA_UNSYNC;
  88. time_maxerror = NTP_PHASE_LIMIT;
  89. time_esterror = NTP_PHASE_LIMIT;
  90. write_unlock_irq(&xtime_lock);
  91. }
  92. /*
  93.  * timer_interrupt() needs to keep up the real-time clock,
  94.  * as well as call the "do_timer()" routine every clocktick
  95.  */
  96. #ifdef CONFIG_SMP
  97. extern __u16 boot_cpu_addr;
  98. #endif
  99. static void do_comparator_interrupt(struct pt_regs *regs, __u16 error_code)
  100. {
  101. int cpu = smp_processor_id();
  102. irq_enter(cpu, 0);
  103. /*
  104.  * set clock comparator for next tick
  105.  */
  106.         S390_lowcore.jiffy_timer += CLK_TICKS_PER_JIFFY;
  107.         asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
  108. #ifdef CONFIG_SMP
  109. if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr)
  110. write_lock(&xtime_lock);
  111. update_process_times(user_mode(regs));
  112. if (S390_lowcore.cpu_data.cpu_addr == boot_cpu_addr) {
  113. do_timer(regs);
  114. write_unlock(&xtime_lock);
  115. }
  116. #else
  117. do_timer(regs);
  118. #endif
  119. irq_exit(cpu, 0);
  120. }
  121. /*
  122.  * Start the clock comparator on the current CPU
  123.  */
  124. void init_cpu_timer(void)
  125. {
  126. unsigned long cr0;
  127.         /* allow clock comparator timer interrupt */
  128.         asm volatile ("STCTG 0,0,%0" : "=m" (cr0) : : "memory");
  129.         cr0 |= 0x800;
  130.         asm volatile ("LCTLG 0,0,%0" : : "m" (cr0) : "memory");
  131. S390_lowcore.jiffy_timer = (__u64) jiffies * CLK_TICKS_PER_JIFFY;
  132. S390_lowcore.jiffy_timer += init_timer_cc + CLK_TICKS_PER_JIFFY;
  133. asm volatile ("SCKC %0" : : "m" (S390_lowcore.jiffy_timer));
  134. }
  135. /*
  136.  * Initialize the TOD clock and the CPU timer of
  137.  * the boot cpu.
  138.  */
  139. void __init time_init(void)
  140. {
  141.         __u64 set_time_cc;
  142. int cc;
  143.         /* kick the TOD clock */
  144.         asm volatile ("STCK %1nt"
  145.                       "IPM  %0nt"
  146.                       "SRL  %0,28" : "=r" (cc), "=m" (init_timer_cc));
  147.         switch (cc) {
  148.         case 0: /* clock in set state: all is fine */
  149.                 break;
  150.         case 1: /* clock in non-set state: FIXME */
  151.                 printk("time_init: TOD clock in non-set staten");
  152.                 break;
  153.         case 2: /* clock in error state: FIXME */
  154.                 printk("time_init: TOD clock in error staten");
  155.                 break;
  156.         case 3: /* clock in stopped or not-operational state: FIXME */
  157.                 printk("time_init: TOD clock stopped/non-operationaln");
  158.                 break;
  159.         }
  160. /* set xtime */
  161.         set_time_cc = init_timer_cc - 0x8126d60e46000000LL +
  162.                       (0x3c26700LL*1000000*4096);
  163.         tod_to_timeval(set_time_cc, &xtime);
  164.         /* request the 0x1004 external interrupt */
  165.         if (register_external_interrupt(0x1004, do_comparator_interrupt) != 0)
  166.                 panic("Couldn't request external interrupt 0x1004");
  167.         /* init CPU timer */
  168.         init_cpu_timer();
  169. }