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 + -
显示快捷键?