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

📄 timer_hpet.c

📁 linux-2.6.15.6
💻 C
字号:
/* * This code largely moved from arch/i386/kernel/time.c. * See comments there for proper credits. */#include <linux/spinlock.h>#include <linux/init.h>#include <linux/timex.h>#include <linux/errno.h>#include <linux/string.h>#include <linux/jiffies.h>#include <asm/timer.h>#include <asm/io.h>#include <asm/processor.h>#include "io_ports.h"#include "mach_timer.h"#include <asm/hpet.h>static unsigned long hpet_usec_quotient __read_mostly;	/* convert hpet clks to usec */static unsigned long tsc_hpet_quotient __read_mostly;	/* convert tsc to hpet clks */static unsigned long hpet_last; 	/* hpet counter value at last tick*/static unsigned long last_tsc_low;	/* lsb 32 bits of Time Stamp Counter */static unsigned long last_tsc_high; 	/* msb 32 bits of Time Stamp Counter */static unsigned long long monotonic_base;static seqlock_t monotonic_lock = SEQLOCK_UNLOCKED;/* convert from cycles(64bits) => nanoseconds (64bits) *  basic equation: *		ns = cycles / (freq / ns_per_sec) *		ns = cycles * (ns_per_sec / freq) *		ns = cycles * (10^9 / (cpu_khz * 10^3)) *		ns = cycles * (10^6 / cpu_khz) * *	Then we use scaling math (suggested by george@mvista.com) to get: *		ns = cycles * (10^6 * SC / cpu_khz) / SC *		ns = cycles * cyc2ns_scale / SC * *	And since SC is a constant power of two, we can convert the div *  into a shift. * *  We can use khz divisor instead of mhz to keep a better percision, since *  cyc2ns_scale is limited to 10^6 * 2^10, which fits in 32 bits. *  (mathieu.desnoyers@polymtl.ca) * *			-johnstul@us.ibm.com "math is hard, lets go shopping!" */static unsigned long cyc2ns_scale;#define CYC2NS_SCALE_FACTOR 10 /* 2^10, carefully chosen */static inline void set_cyc2ns_scale(unsigned long cpu_khz){	cyc2ns_scale = (1000000 << CYC2NS_SCALE_FACTOR)/cpu_khz;}static inline unsigned long long cycles_2_ns(unsigned long long cyc){	return (cyc * cyc2ns_scale) >> CYC2NS_SCALE_FACTOR;}static unsigned long long monotonic_clock_hpet(void){	unsigned long long last_offset, this_offset, base;	unsigned seq;	/* atomically read monotonic base & last_offset */	do {		seq = read_seqbegin(&monotonic_lock);		last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;		base = monotonic_base;	} while (read_seqretry(&monotonic_lock, seq));	/* Read the Time Stamp Counter */	rdtscll(this_offset);	/* return the value in ns */	return base + cycles_2_ns(this_offset - last_offset);}static unsigned long get_offset_hpet(void){	register unsigned long eax, edx;	eax = hpet_readl(HPET_COUNTER);	eax -= hpet_last;	/* hpet delta */	eax = min(hpet_tick, eax);	/*         * Time offset = (hpet delta) * ( usecs per HPET clock )	 *             = (hpet delta) * ( usecs per tick / HPET clocks per tick)	 *             = (hpet delta) * ( hpet_usec_quotient ) / (2^32)	 *	 * Where,	 * hpet_usec_quotient = (2^32 * usecs per tick)/HPET clocks per tick	 *	 * Using a mull instead of a divl saves some cycles in critical path.         */	ASM_MUL64_REG(eax, edx, hpet_usec_quotient, eax);	/* our adjusted time offset in microseconds */	return edx;}static void mark_offset_hpet(void){	unsigned long long this_offset, last_offset;	unsigned long offset;	write_seqlock(&monotonic_lock);	last_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;	rdtsc(last_tsc_low, last_tsc_high);	if (hpet_use_timer)		offset = hpet_readl(HPET_T0_CMP) - hpet_tick;	else		offset = hpet_readl(HPET_COUNTER);	if (unlikely(((offset - hpet_last) >= (2*hpet_tick)) && (hpet_last != 0))) {		int lost_ticks = ((offset - hpet_last) / hpet_tick) - 1;		jiffies_64 += lost_ticks;	}	hpet_last = offset;	/* update the monotonic base value */	this_offset = ((unsigned long long)last_tsc_high<<32)|last_tsc_low;	monotonic_base += cycles_2_ns(this_offset - last_offset);	write_sequnlock(&monotonic_lock);}static void delay_hpet(unsigned long loops){	unsigned long hpet_start, hpet_end;	unsigned long eax;	/* loops is the number of cpu cycles. Convert it to hpet clocks */	ASM_MUL64_REG(eax, loops, tsc_hpet_quotient, loops);	hpet_start = hpet_readl(HPET_COUNTER);	do {		rep_nop();		hpet_end = hpet_readl(HPET_COUNTER);	} while ((hpet_end - hpet_start) < (loops));}static struct timer_opts timer_hpet;static int __init init_hpet(char* override){	unsigned long result, remain;	/* check clock override */	if (override[0] && strncmp(override,"hpet",4))		return -ENODEV;	if (!is_hpet_enabled())		return -ENODEV;	printk("Using HPET for gettimeofday\n");	if (cpu_has_tsc) {		unsigned long tsc_quotient = calibrate_tsc_hpet(&tsc_hpet_quotient);		if (tsc_quotient) {			/* report CPU clock rate in Hz.			 * The formula is (10^6 * 2^32) / (2^32 * 1 / (clocks/us)) =			 * clock/second. Our precision is about 100 ppm.			 */			{	unsigned long eax=0, edx=1000;				ASM_DIV64_REG(cpu_khz, edx, tsc_quotient,						eax, edx);				printk("Detected %u.%03u MHz processor.\n",					cpu_khz / 1000, cpu_khz % 1000);			}			set_cyc2ns_scale(cpu_khz);		}		/* set this only when cpu_has_tsc */		timer_hpet.read_timer = read_timer_tsc;	}	/*	 * Math to calculate hpet to usec multiplier	 * Look for the comments at get_offset_hpet()	 */	ASM_DIV64_REG(result, remain, hpet_tick, 0, KERNEL_TICK_USEC);	if (remain > (hpet_tick >> 1))		result++; /* rounding the result */	hpet_usec_quotient = result;	return 0;}static int hpet_resume(void){	write_seqlock(&monotonic_lock);	/* Assume this is the last mark offset time */	rdtsc(last_tsc_low, last_tsc_high);	if (hpet_use_timer)		hpet_last = hpet_readl(HPET_T0_CMP) - hpet_tick;	else		hpet_last = hpet_readl(HPET_COUNTER);	write_sequnlock(&monotonic_lock);	return 0;}/************************************************************//* tsc timer_opts struct */static struct timer_opts timer_hpet __read_mostly = {	.name = 		"hpet",	.mark_offset =		mark_offset_hpet,	.get_offset =		get_offset_hpet,	.monotonic_clock =	monotonic_clock_hpet,	.delay = 		delay_hpet,	.resume	=		hpet_resume,};struct init_timer_opts __initdata timer_hpet_init = {	.init =	init_hpet,	.opts = &timer_hpet,};

⌨️ 快捷键说明

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