time.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 661 行 · 第 1/2 页
C
661 行
/* * linux/arch/cris/kernel/time.c * * Copyright (C) 1991, 1992, 1995 Linus Torvalds * Copyright (C) 1999, 2000, 2001, 2002, 2003 Axis Communications AB * * 1994-07-02 Alan Modra * fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime * 1995-03-26 Markus Kuhn * fixed 500 ms bug at call to set_rtc_mmss, fixed DS12887 * precision CMOS clock update * 1996-05-03 Ingo Molnar * fixed time warps in do_[slow|fast]_gettimeoffset() * 1997-09-10 Updated NTP code according to technical memorandum Jan '96 * "A Kernel Model for Precision Timekeeping" by Dave Mills * * Linux/CRIS specific code: * * Authors: Bjorn Wesen * Johan Adolfsson * * 2002-03-04 Johan Adolfsson * Use prescale timer at 25000 Hz instead of the baudrate timer at * 19200 to get rid of the 64ppm to fast timer (and we get better * resolution within a jiffie as well. * 2002-03-05 Johan Adolfsson * Use prescaler in do_slow_gettimeoffset() to get 1 us resolution (40ns) * 2002-09-06 Johan Adolfsson * Handle lost ticks by checking wall_jiffies, more efficient code * by using local vars and not the pointer argument. * */#include <linux/errno.h>#include <linux/sched.h>#include <linux/init.h>#include <linux/kernel.h>#include <linux/param.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/time.h>#include <linux/delay.h>#include <asm/segment.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/delay.h>#include <asm/rtc.h>#include <linux/timex.h>#include <linux/config.h>#include <asm/svinto.h>#define CRIS_TEST_TIMERS 0static int have_rtc; /* used to remember if we have an RTC or not *//* define this if you need to use print_timestamp *//* it will make jiffies at 96 hz instead of 100 hz though */#undef USE_CASCADE_TIMERSextern int setup_etrax_irq(int, struct irqaction *);#define TICK_SIZE tickextern unsigned long wall_jiffies;/* The timers count from their initial value down to 1 * The R_TIMER0_DATA counts down when R_TIM_PRESC_STATUS reaches halv * of the divider value. */ unsigned long get_ns_in_jiffie(void){ unsigned char timer_count, t1; unsigned short presc_count; unsigned long ns; unsigned long flags; save_flags(flags); cli(); timer_count = *R_TIMER0_DATA; presc_count = *R_TIM_PRESC_STATUS; /* presc_count might be wrapped */ t1 = *R_TIMER0_DATA; if (timer_count != t1){ /* it wrapped, read prescaler again... */ presc_count = *R_TIM_PRESC_STATUS; timer_count = t1; } restore_flags(flags); if (presc_count >= PRESCALE_VALUE/2 ){ presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; } else { presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; } ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + ( (presc_count) * (1000000000/PRESCALE_FREQ)); return ns;}/* Convert the clkdiv_low and clkdivb_high fiels in timer_data * (from *R_TIMER_DATA) to nanoseconds (67 ns resolution) */unsigned long timer_data_to_ns(unsigned long timer_data) {/* low (clkdiv_low lsb toggles with 7.3728MHz so it counts * with 14.7456 MHz = 67.816 ns (0-17361ns) * high (clkdiv_high lsb toggles with 38.4kHz so it counts * with 76.8kHz = 13020.833 ns (0-3333333 ns) * By checking bit 9,8,7 we can now how to compensate the low value * to get a 67 ns resolution all the way.Example of R_TIMER_DATA values: bit 98 7 low 9 87 offset0289DC00 00 000 0 0 00 00289DC41 00 010 64 0 01 00289DC81 00 100 128 0 10 00289DDC0 01 110 192 1 11 0 13020 = 192 0289DD01 01 000 0 256 1 00 +256 0289DD41 01 010 64 320 1 01 +256 0288DE80 10 100 128 384 0 10 0: -128 26040= 384 0288DEC1 10 110 192 448 0 11 64 -128 0288DE01 10 000 0 512 128 +128 0288DF40 11 010 64 576 192 +128 39060 0288DF81 11 100 128 640 256 +128 0288DFC1 11 110 192 704 320 +128 ..393 */ static const short timer_data_add[8] = { 0, /* 00 0 */ 0, /* 00 1 */ 256, /* 01 0 */ 0, /* 01 1 */ 128, /* 10 0 */ -128,/* 10 1 */ 128, /* 11 0 */ 128 /* 11 1 */ }; unsigned long ns; unsigned long low; unsigned long high; high = (((timer_data & 0x0000FE00)>>8) * 13020833)/1000; ns = high; low = timer_data & 0xFF; low += timer_data_add[(timer_data >>7) & 0x7]; ns += (low * 67816)/1000; return ns;} /* timer_data_to_ns */#if CRIS_TEST_TIMERS #define NS_TEST_SIZE 4000static unsigned long ns_test[NS_TEST_SIZE];void cris_test_timers(void){ int i;#if 0 for (i = 0; i < NS_TEST_SIZE; i++) { ns_test[i] = *R_TIMER0_DATA | (*R_TIM_PRESC_STATUS<<16); } for (i = 1; i < NS_TEST_SIZE; i++) { printk("%4i. %lu %lu %09lu ns \n", i, ns_test[i]&0x0FFFF, (ns_test[i]>>16), get_ns_in_jiffie_from_data(ns_test[i]&0x0FFFF, ns_test[i]>>16)); }#else for (i = 0; i < NS_TEST_SIZE; i++) { ns_test[i] = get_ns_in_jiffie(); } for (i = 1; i < NS_TEST_SIZE; i++) { printk("%4i. %09lu ns diff %li ns\n", i, ns_test[i], ns_test[i]- ns_test[i-1]); }#endif}#endifstatic unsigned long do_slow_gettimeoffset(void){ unsigned long count, t1; unsigned long usec_count = 0; unsigned short presc_count; static unsigned long count_p = TIMER0_DIV;/* for the first call after boot */ static unsigned long jiffies_p = 0; /* * cache volatile jiffies temporarily; we have IRQs turned off. */ unsigned long jiffies_t; /* The timer interrupt comes from Etrax timer 0. In order to get * better precision, we check the current value. It might have * underflowed already though. */#ifndef CONFIG_SVINTO_SIM /* Not available in the xsim simulator. */ count = *R_TIMER0_DATA; presc_count = *R_TIM_PRESC_STATUS; /* presc_count might be wrapped */ t1 = *R_TIMER0_DATA; if (count != t1){ /* it wrapped, read prescaler again... */ presc_count = *R_TIM_PRESC_STATUS; count = t1; }#else count = 0; presc_count = 0;#endif jiffies_t = jiffies; /* * avoiding timer inconsistencies (they are rare, but they happen)... * there are one problem that must be avoided here: * 1. the timer counter underflows */ if( jiffies_t == jiffies_p ) { if( count > count_p ) { /* Timer wrapped, use new count and prescale * increase the time corresponding to one jiffie */ usec_count = 1000000/HZ; } } else jiffies_p = jiffies_t; count_p = count; if (presc_count >= PRESCALE_VALUE/2 ){ presc_count = PRESCALE_VALUE - presc_count + PRESCALE_VALUE/2; } else { presc_count = PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2; } /* Convert timer value to usec */ usec_count += ( (TIMER0_DIV - count) * (1000000/HZ)/TIMER0_DIV ) + (( (presc_count) * (1000000000/PRESCALE_FREQ))/1000); return usec_count;}#define do_gettimeoffset() do_slow_gettimeoffset()/* * This version of gettimeofday has near microsecond resolution. */void do_gettimeofday(struct timeval *tv){ unsigned long flags; unsigned long usec, sec; save_flags(flags); cli(); usec = do_gettimeoffset(); { unsigned long lost = jiffies - wall_jiffies; if (lost) usec += lost * (1000000 / HZ); } sec = xtime.tv_sec; usec += xtime.tv_usec; restore_flags(flags); while (usec >= 1000000) { usec -= 1000000; sec++; } tv->tv_sec = sec; tv->tv_usec = usec;}void do_settimeofday(struct timeval *tv){ unsigned long flags; signed long new_usec, new_sec; save_flags(flags); cli(); /* This is revolting. We need to set the xtime.tv_usec * correctly. However, the value in this location is * is value at the last tick. * Discover what correction gettimeofday * would have done, and then undo it! */ new_usec = tv->tv_usec; new_usec -= do_gettimeoffset(); new_usec -= (jiffies - wall_jiffies) * (1000000 / HZ); new_sec = tv->tv_sec; while (new_usec < 0) { new_usec += 1000000; new_sec--; } xtime.tv_sec = new_sec; xtime.tv_usec = new_usec; time_adjust = 0; /* stop active adjtime() */ time_status |= STA_UNSYNC; time_state = TIME_ERROR; /* p. 24, (a) */ time_maxerror = NTP_PHASE_LIMIT; time_esterror = NTP_PHASE_LIMIT; restore_flags(flags);}/* * BUG: This routine does not handle hour overflow properly; it just * sets the minutes. Usually you'll only notice that after reboot! */static int set_rtc_mmss(unsigned long nowtime){ int retval = 0; int real_seconds, real_minutes, cmos_minutes; printk(KERN_DEBUG "set_rtc_mmss(%lu)\n", nowtime);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?