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

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *
  3.  * BRIEF MODULE DESCRIPTION
  4.  * Galileo EV96100 rtc routines.
  5.  *
  6.  * Copyright 2000 MontaVista Software Inc.
  7.  * Author: MontaVista Software, Inc.
  8.  *          ppopov@mvista.com or source@mvista.com
  9.  *
  10.  * This file was derived from Carsten Langgaard's
  11.  * arch/mips/mips-boards/atlas/atlas_rtc.c.
  12.  *
  13.  * Carsten Langgaard, carstenl@mips.com
  14.  * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
  15.  *
  16.  *  This program is free software; you can redistribute  it and/or modify it
  17.  *  under  the terms of  the GNU General  Public License as published by the
  18.  *  Free Software Foundation;  either version 2 of the  License, or (at your
  19.  *  option) any later version.
  20.  *
  21.  *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
  22.  *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
  23.  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
  24.  *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
  25.  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  26.  *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
  27.  *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
  28.  *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
  29.  *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  30.  *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31.  *
  32.  *  You should have received a copy of the  GNU General Public License along
  33.  *  with this program; if not, write  to the Free Software Foundation, Inc.,
  34.  *  675 Mass Ave, Cambridge, MA 02139, USA.
  35.  */
  36. #include <linux/init.h>
  37. #include <linux/kernel_stat.h>
  38. #include <linux/sched.h>
  39. #include <linux/spinlock.h>
  40. #include <linux/timex.h>
  41. #include <asm/mipsregs.h>
  42. #include <asm/ptrace.h>
  43. #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
  44. extern volatile unsigned long wall_jiffies;
  45. unsigned long missed_heart_beats = 0;
  46. static unsigned long r4k_offset; /* Amount to increment compare reg each time */
  47. static unsigned long r4k_cur;    /* What counter should be at next timer irq */
  48. extern rwlock_t xtime_lock;
  49. static inline void ack_r4ktimer(unsigned long newval)
  50. {
  51. write_32bit_cp0_register(CP0_COMPARE, newval);
  52. }
  53. static int set_rtc_mmss(unsigned long nowtime)
  54. {
  55.     /* EV96100 does not have a real time clock */
  56.     int retval = 0;
  57.     return retval;
  58. }
  59. /*
  60.  * Figure out the r4k offset, the amount to increment the compare
  61.  * register for each time tick.
  62.  * Use the RTC to calculate offset.
  63.  */
  64. static unsigned long __init cal_r4koff(void)
  65. {
  66. unsigned long count;
  67.         count = 300000000/2;
  68. return (count / HZ);
  69. }
  70. static unsigned long __init get_mips_time(void)
  71. {
  72. unsigned int year, mon, day, hour, min, sec;
  73.         year = 2000;
  74.         mon = 10;
  75.         day = 31;
  76.         hour = 0;
  77.         min = 0;
  78.         sec = 0;
  79. return mktime(year, mon, day, hour, min, sec);
  80. }
  81. /*
  82.  * called from start_kernel()
  83.  */
  84. void __init time_init(void)
  85. {
  86.         unsigned int est_freq;
  87. r4k_offset = cal_r4koff();
  88. est_freq = 2*r4k_offset*HZ;
  89. est_freq += 5000;    /* round */
  90. est_freq -= est_freq%10000;
  91. printk("CPU frequency %d.%02d MHzn", est_freq/1000000,
  92.        (est_freq%1000000)*100/1000000);
  93. r4k_cur = (read_32bit_cp0_register(CP0_COUNT) + r4k_offset);
  94. write_32bit_cp0_register(CP0_COMPARE, r4k_cur);
  95.         /* FIX ME */
  96. change_cp0_status(ST0_IM, IE_IRQ5);
  97. }
  98. /* This is for machines which generate the exact clock. */
  99. #define USECS_PER_JIFFY (1000000/HZ)
  100. /* Cycle counter value at the previous timer interrupt.. */
  101. static unsigned int timerhi = 0, timerlo = 0;
  102. /*
  103.  * FIXME: Does playing with the RP bit in c0_status interfere with this code?
  104.  */
  105. static unsigned long do_fast_gettimeoffset(void)
  106. {
  107. u32 count;
  108. unsigned long res, tmp;
  109. /* Last jiffy when do_fast_gettimeoffset() was called. */
  110. static unsigned long last_jiffies=0;
  111. unsigned long quotient;
  112. /*
  113.  * Cached "1/(clocks per usec)*2^32" value.
  114.  * It has to be recalculated once each jiffy.
  115.  */
  116. static unsigned long cached_quotient=0;
  117. tmp = jiffies;
  118. quotient = cached_quotient;
  119. if (tmp && last_jiffies != tmp) {
  120. last_jiffies = tmp;
  121. __asm__(".settnoreordernt"
  122. ".settnoatnt"
  123. ".settmips3nt"
  124. "lwut%0,%2nt"
  125. "dsll32t$1,%1,0nt"
  126. "ort$1,$1,%0nt"
  127. "ddivut$0,$1,%3nt"
  128. "mflot$1nt"
  129. "dsll32t%0,%4,0nt"
  130. "nopnt"
  131. "ddivut$0,%0,$1nt"
  132. "mflot%0nt"
  133. ".settmips0nt"
  134. ".settatnt"
  135. ".settreorder"
  136. :"=&r" (quotient)
  137. :"r" (timerhi),
  138.  "m" (timerlo),
  139.  "r" (tmp),
  140.  "r" (USECS_PER_JIFFY));
  141. cached_quotient = quotient;
  142. }
  143. /* Get last timer tick in absolute kernel time */
  144. count = read_32bit_cp0_register(CP0_COUNT);
  145. /* .. relative to previous jiffy (32 bits is enough) */
  146. count -= timerlo;
  147. __asm__("multut%1,%2nt"
  148. "mfhit%0"
  149. :"=r" (res)
  150. :"r" (count),
  151.  "r" (quotient));
  152. /*
  153.    * Due to possible jiffies inconsistencies, we need to check
  154.  * the result so that we'll get a timer that is monotonic.
  155.  */
  156. if (res >= USECS_PER_JIFFY)
  157. res = USECS_PER_JIFFY-1;
  158. return res;
  159. }
  160. void do_gettimeofday(struct timeval *tv)
  161. {
  162. unsigned int flags;
  163. read_lock_irqsave (&xtime_lock, flags);
  164. *tv = xtime;
  165. tv->tv_usec += do_fast_gettimeoffset();
  166. /*
  167.  * xtime is atomically updated in timer_bh. jiffies - wall_jiffies
  168.  * is nonzero if the timer bottom half hasnt executed yet.
  169.  */
  170. if (jiffies - wall_jiffies)
  171. tv->tv_usec += USECS_PER_JIFFY;
  172. read_unlock_irqrestore (&xtime_lock, flags);
  173. if (tv->tv_usec >= 1000000) {
  174. tv->tv_usec -= 1000000;
  175. tv->tv_sec++;
  176. }
  177. }
  178. void do_settimeofday(struct timeval *tv)
  179. {
  180. write_lock_irq (&xtime_lock);
  181. /* This is revolting. We need to set the xtime.tv_usec correctly.
  182.  * However, the value in this location is is value at the last tick.
  183.  * Discover what correction gettimeofday would have done, and then
  184.  * undo it!
  185.  */
  186. tv->tv_usec -= do_fast_gettimeoffset();
  187. if (tv->tv_usec < 0) {
  188. tv->tv_usec += 1000000;
  189. tv->tv_sec--;
  190. }
  191. xtime = *tv;
  192. time_adjust = 0; /* stop active adjtime() */
  193. time_status |= STA_UNSYNC;
  194. time_maxerror = NTP_PHASE_LIMIT;
  195. time_esterror = NTP_PHASE_LIMIT;
  196. write_unlock_irq (&xtime_lock);
  197. }
  198. /*
  199.  * There are a lot of conceptually broken versions of the MIPS timer interrupt
  200.  * handler floating around.  This one is rather different, but the algorithm
  201.  * is probably more robust.
  202.  */
  203. void mips_timer_interrupt(struct pt_regs *regs)
  204. {
  205.         int irq = 7; /* FIX ME */
  206. if (r4k_offset == 0) {
  207.             goto null;
  208.         }
  209. do {
  210. kstat.irqs[0][irq]++;
  211. do_timer(regs);
  212. r4k_cur += r4k_offset;
  213. ack_r4ktimer(r4k_cur);
  214. } while (((unsigned long)read_32bit_cp0_register(CP0_COUNT)
  215.                     - r4k_cur) < 0x7fffffff);
  216. return;
  217. null:
  218. ack_r4ktimer(0);
  219. }