⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 time.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
static cycle_t rtc_read(void){	return (cycle_t)get_rtc();}static cycle_t timebase_read(void){	return (cycle_t)get_tb();}void update_vsyscall(struct timespec *wall_time, struct clocksource *clock){	u64 t2x, stamp_xsec;	if (clock != &clocksource_timebase)		return;	/* Make userspace gettimeofday spin until we're done. */	++vdso_data->tb_update_count;	smp_mb();	/* XXX this assumes clock->shift == 22 */	/* 4611686018 ~= 2^(20+64-22) / 1e9 */	t2x = (u64) clock->mult * 4611686018ULL;	stamp_xsec = (u64) xtime.tv_nsec * XSEC_PER_SEC;	do_div(stamp_xsec, 1000000000);	stamp_xsec += (u64) xtime.tv_sec * XSEC_PER_SEC;	update_gtod(clock->cycle_last, stamp_xsec, t2x);}void update_vsyscall_tz(void){	/* Make userspace gettimeofday spin until we're done. */	++vdso_data->tb_update_count;	smp_mb();	vdso_data->tz_minuteswest = sys_tz.tz_minuteswest;	vdso_data->tz_dsttime = sys_tz.tz_dsttime;	smp_mb();	++vdso_data->tb_update_count;}void __init clocksource_init(void){	struct clocksource *clock;	if (__USE_RTC())		clock = &clocksource_rtc;	else		clock = &clocksource_timebase;	clock->mult = clocksource_hz2mult(tb_ticks_per_sec, clock->shift);	if (clocksource_register(clock)) {		printk(KERN_ERR "clocksource: %s is already registered\n",		       clock->name);		return;	}	printk(KERN_INFO "clocksource: %s mult[%x] shift[%d] registered\n",	       clock->name, clock->mult, clock->shift);}static int decrementer_set_next_event(unsigned long evt,				      struct clock_event_device *dev){	__get_cpu_var(decrementer_next_tb) = get_tb_or_rtc() + evt;	set_dec(evt);	return 0;}static void decrementer_set_mode(enum clock_event_mode mode,				 struct clock_event_device *dev){	if (mode != CLOCK_EVT_MODE_ONESHOT)		decrementer_set_next_event(DECREMENTER_MAX, dev);}static void register_decrementer_clockevent(int cpu){	struct clock_event_device *dec = &per_cpu(decrementers, cpu);	*dec = decrementer_clockevent;	dec->cpumask = cpumask_of_cpu(cpu);	printk(KERN_DEBUG "clockevent: %s mult[%lx] shift[%d] cpu[%d]\n",	       dec->name, dec->mult, dec->shift, cpu);	clockevents_register_device(dec);}void init_decrementer_clockevent(void){	int cpu = smp_processor_id();	decrementer_clockevent.mult = div_sc(ppc_tb_freq, NSEC_PER_SEC,					     decrementer_clockevent.shift);	decrementer_clockevent.max_delta_ns =		clockevent_delta2ns(DECREMENTER_MAX, &decrementer_clockevent);	decrementer_clockevent.min_delta_ns =		clockevent_delta2ns(2, &decrementer_clockevent);	register_decrementer_clockevent(cpu);}void secondary_cpu_time_init(void){	/* FIME: Should make unrelatred change to move snapshot_timebase	 * call here ! */	register_decrementer_clockevent(smp_processor_id());}/* This function is only called on the boot processor */void __init time_init(void){	unsigned long flags;	struct div_result res;	u64 scale, x;	unsigned shift;	if (__USE_RTC()) {		/* 601 processor: dec counts down by 128 every 128ns */		ppc_tb_freq = 1000000000;		tb_last_jiffy = get_rtcl();	} else {		/* Normal PowerPC with timebase register */		ppc_md.calibrate_decr();		printk(KERN_DEBUG "time_init: decrementer frequency = %lu.%.6lu MHz\n",		       ppc_tb_freq / 1000000, ppc_tb_freq % 1000000);		printk(KERN_DEBUG "time_init: processor frequency   = %lu.%.6lu MHz\n",		       ppc_proc_freq / 1000000, ppc_proc_freq % 1000000);		tb_last_jiffy = get_tb();	}	tb_ticks_per_jiffy = ppc_tb_freq / HZ;	tb_ticks_per_sec = ppc_tb_freq;	tb_ticks_per_usec = ppc_tb_freq / 1000000;	tb_to_us = mulhwu_scale_factor(ppc_tb_freq, 1000000);	calc_cputime_factors();	/*	 * Calculate the length of each tick in ns.  It will not be	 * exactly 1e9/HZ unless ppc_tb_freq is divisible by HZ.	 * We compute 1e9 * tb_ticks_per_jiffy / ppc_tb_freq,	 * rounded up.	 */	x = (u64) NSEC_PER_SEC * tb_ticks_per_jiffy + ppc_tb_freq - 1;	do_div(x, ppc_tb_freq);	tick_nsec = x;	last_tick_len = x << TICKLEN_SCALE;	/*	 * Compute ticklen_to_xs, which is a factor which gets multiplied	 * by (last_tick_len << TICKLEN_SHIFT) to get a tb_to_xs value.	 * It is computed as:	 * ticklen_to_xs = 2^N / (tb_ticks_per_jiffy * 1e9)	 * where N = 64 + 20 - TICKLEN_SCALE - TICKLEN_SHIFT	 * which turns out to be N = 51 - SHIFT_HZ.	 * This gives the result as a 0.64 fixed-point fraction.	 * That value is reduced by an offset amounting to 1 xsec per	 * 2^31 timebase ticks to avoid problems with time going backwards	 * by 1 xsec when we do timer_recalc_offset due to losing the	 * fractional xsec.  That offset is equal to ppc_tb_freq/2^51	 * since there are 2^20 xsec in a second.	 */	div128_by_32((1ULL << 51) - ppc_tb_freq, 0,		     tb_ticks_per_jiffy << SHIFT_HZ, &res);	div128_by_32(res.result_high, res.result_low, NSEC_PER_SEC, &res);	ticklen_to_xs = res.result_low;	/* Compute tb_to_xs from tick_nsec */	tb_to_xs = mulhdu(last_tick_len << TICKLEN_SHIFT, ticklen_to_xs);	/*	 * Compute scale factor for sched_clock.	 * The calibrate_decr() function has set tb_ticks_per_sec,	 * which is the timebase frequency.	 * We compute 1e9 * 2^64 / tb_ticks_per_sec and interpret	 * the 128-bit result as a 64.64 fixed-point number.	 * We then shift that number right until it is less than 1.0,	 * giving us the scale factor and shift count to use in	 * sched_clock().	 */	div128_by_32(1000000000, 0, tb_ticks_per_sec, &res);	scale = res.result_low;	for (shift = 0; res.result_high != 0; ++shift) {		scale = (scale >> 1) | (res.result_high << 63);		res.result_high >>= 1;	}	tb_to_ns_scale = scale;	tb_to_ns_shift = shift;	/* Save the current timebase to pretty up CONFIG_PRINTK_TIME */	boot_tb = get_tb_or_rtc();	write_seqlock_irqsave(&xtime_lock, flags);	/* If platform provided a timezone (pmac), we correct the time */        if (timezone_offset) {		sys_tz.tz_minuteswest = -timezone_offset / 60;		sys_tz.tz_dsttime = 0;        }	do_gtod.varp = &do_gtod.vars[0];	do_gtod.var_idx = 0;	do_gtod.varp->tb_orig_stamp = tb_last_jiffy;	__get_cpu_var(last_jiffy) = tb_last_jiffy;	do_gtod.varp->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;	do_gtod.tb_ticks_per_sec = tb_ticks_per_sec;	do_gtod.varp->tb_to_xs = tb_to_xs;	do_gtod.tb_to_us = tb_to_us;	vdso_data->tb_orig_stamp = tb_last_jiffy;	vdso_data->tb_update_count = 0;	vdso_data->tb_ticks_per_sec = tb_ticks_per_sec;	vdso_data->stamp_xsec = (u64) xtime.tv_sec * XSEC_PER_SEC;	vdso_data->tb_to_xs = tb_to_xs;	time_freq = 0;	write_sequnlock_irqrestore(&xtime_lock, flags);	/* Register the clocksource, if we're not running on iSeries */	if (!firmware_has_feature(FW_FEATURE_ISERIES))		clocksource_init();	init_decrementer_clockevent();}#define FEBRUARY	2#define	STARTOFTIME	1970#define SECDAY		86400L#define SECYR		(SECDAY * 365)#define	leapyear(year)		((year) % 4 == 0 && \				 ((year) % 100 != 0 || (year) % 400 == 0))#define	days_in_year(a) 	(leapyear(a) ? 366 : 365)#define	days_in_month(a) 	(month_days[(a) - 1])static int month_days[12] = {	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};/* * This only works for the Gregorian calendar - i.e. after 1752 (in the UK) */void GregorianDay(struct rtc_time * tm){	int leapsToDate;	int lastYear;	int day;	int MonthOffset[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };	lastYear = tm->tm_year - 1;	/*	 * Number of leap corrections to apply up to end of last year	 */	leapsToDate = lastYear / 4 - lastYear / 100 + lastYear / 400;	/*	 * This year is a leap year if it is divisible by 4 except when it is	 * divisible by 100 unless it is divisible by 400	 *	 * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 was	 */	day = tm->tm_mon > 2 && leapyear(tm->tm_year);	day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] +		   tm->tm_mday;	tm->tm_wday = day % 7;}void to_tm(int tim, struct rtc_time * tm){	register int    i;	register long   hms, day;	day = tim / SECDAY;	hms = tim % SECDAY;	/* Hours, minutes, seconds are easy */	tm->tm_hour = hms / 3600;	tm->tm_min = (hms % 3600) / 60;	tm->tm_sec = (hms % 3600) % 60;	/* Number of years in days */	for (i = STARTOFTIME; day >= days_in_year(i); i++)		day -= days_in_year(i);	tm->tm_year = i;	/* Number of months in days left */	if (leapyear(tm->tm_year))		days_in_month(FEBRUARY) = 29;	for (i = 1; day >= days_in_month(i); i++)		day -= days_in_month(i);	days_in_month(FEBRUARY) = 28;	tm->tm_mon = i;	/* Days are what is left over (+1) from all that. */	tm->tm_mday = day + 1;	/*	 * Determine the day of week	 */	GregorianDay(tm);}/* Auxiliary function to compute scaling factors *//* Actually the choice of a timebase running at 1/4 the of the bus * frequency giving resolution of a few tens of nanoseconds is quite nice. * It makes this computation very precise (27-28 bits typically) which * is optimistic considering the stability of most processor clock * oscillators and the precision with which the timebase frequency * is measured but does not harm. */unsigned mulhwu_scale_factor(unsigned inscale, unsigned outscale){        unsigned mlt=0, tmp, err;        /* No concern for performance, it's done once: use a stupid         * but safe and compact method to find the multiplier.         */          for (tmp = 1U<<31; tmp != 0; tmp >>= 1) {                if (mulhwu(inscale, mlt|tmp) < outscale)			mlt |= tmp;        }          /* We might still be off by 1 for the best approximation.         * A side effect of this is that if outscale is too large         * the returned value will be zero.         * Many corner cases have been checked and seem to work,         * some might have been forgotten in the test however.         */          err = inscale * (mlt+1);        if (err <= inscale/2)		mlt++;        return mlt;}/* * Divide a 128-bit dividend by a 32-bit divisor, leaving a 128 bit * result. */void div128_by_32(u64 dividend_high, u64 dividend_low,		  unsigned divisor, struct div_result *dr){	unsigned long a, b, c, d;	unsigned long w, x, y, z;	u64 ra, rb, rc;	a = dividend_high >> 32;	b = dividend_high & 0xffffffff;	c = dividend_low >> 32;	d = dividend_low & 0xffffffff;	w = a / divisor;	ra = ((u64)(a - (w * divisor)) << 32) + b;	rb = ((u64) do_div(ra, divisor) << 32) + c;	x = ra;	rc = ((u64) do_div(rb, divisor) << 32) + d;	y = rb;	do_div(rc, divisor);	z = rc;	dr->result_high = ((u64)w << 32) + x;	dr->result_low  = ((u64)y << 32) + z;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -