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

📄 rtl_time.c

📁 rtlinux3.0 的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * rtl_time.c * * architecture-dependent clock support * * Written by Michael Barabanov * Copyright  Finite State Machine Labs Inc. 1998-1999 * Released under the terms of the GPL Version 2 * */#include <rtl_conf.h>#include <linux/module.h>#include <linux/kernel.h>#include <linux/config.h>#include <asm/smp.h>#include <asm/io.h>#include <linux/errno.h>#include <asm/system.h>#include <linux/irq.h>#include <asm/hw_irq.h>#include <linux/sched.h>#include <linux/timex.h>#include <linux/mc146818rtc.h>#include <rtl.h>#include <rtl_core.h>#include <rtl_debug.h>#include <rtl_sync.h>#include <rtl_time.h>/* #define CONFIG_RTL_FAST_8254 */int notsc=0;MODULE_PARM(notsc,"i");int _8254_latency = 0;#ifndef cpu_has_tsc#define cpu_has_tsc \	(boot_cpu_data.x86_capability & X86_FEATURE_TSC)#endifhrtime_t _gethrtime(struct rtl_clock *c){	return gethrtime();}struct rtl_clock _i8254_clock;#ifdef CONFIG_X86_LOCAL_APICstruct rtl_clock _apic_clock[NR_CPUS];#endifextern void (*kd_mksound)(unsigned int hz, unsigned int ticks);static hrtime_t (*rtl_do_get_time)(void);static hrtime_t hrtime_resolution;static long LATCH_NS;static long MAX_LATCH_ONESHOT;/* getting global time from 8254 */#define READ_CNT0(var) \do { var = inb(0x40); var |= (inb(0x40) << 8); } while (0)#define READ_CNT2(var) \do { var = inb(0x42); var |= (inb(0x42) << 8); } while (0)#define LATCH_CNT0() \outb(0xd2, 0x43);#define LATCH_CNT0_AND_2() \outb(0xda, 0x43);#define LATCH_CNT2() \outb(0xd8, 0x43);#define WRITE_COUNTER_ZERO16(x) do { \	outb(x&0xff,0x40); outb((x>>8)&0xff,0x40);\      	clock_counter =x; \} while (0)#define WRITE_COUNTER_ZERO8(x) do { \	outb(x&0xff,0x40); \	clock_counter =x; \} while (0)#ifdef CONFIG_RTL_FAST_8254#define WRITE_COUNTER_ZERO_ONESHOT(x) WRITE_COUNTER_ZERO8(x)#else #define WRITE_COUNTER_ZERO_ONESHOT(x) WRITE_COUNTER_ZERO16(x)#endifstatic volatile int last_c2;unsigned long scaler_8254_to_hrtime;  /* =8380965  ns*100 */unsigned long scaler_hrtime_to_8254;#define LATCH2 0x8000/*static */spinlock_t lock8254;/*static */spinlock_t lock_linuxtime;hrtime_t gethrtime(void){	return rtl_do_get_time();}hrtime_t gethrtimeres(void){	return hrtime_resolution;}hrtime_t base_time;hrtime_t last_8254_time;long offset_time;hrtime_t global_8254_gettime (void){	register unsigned int c2;	int flags;	long t;	rtl_spin_lock_irqsave (&lock8254, flags);	LATCH_CNT2();	READ_CNT2(c2);	offset_time += ((c2 < last_c2) ? (last_c2 - c2) / 2 : (last_c2 - c2 + LATCH2) / 2);	last_c2 = c2;	if (offset_time >= CLOCK_TICK_RATE) {		offset_time -= CLOCK_TICK_RATE;		base_time += HRTICKS_PER_SEC;	}#if HRTICKS_PER_SEC != CLOCK_TICK_RATE	__asm__("shl $10, %%eax\n\t"		"mul %%ebx\n\t"	:"=d" (t) : "b" (scaler_8254_to_hrtime), "a" (offset_time));#else	t = offset_time;#endif	last_8254_time = base_time + t;	rtl_spin_unlock_irqrestore (&lock8254, flags);	return last_8254_time;}/* getting global time from Pentium TSC */static unsigned long scaler_pentium_to_hrtime = 0;int can_change_latch2;int I8253_channel2_free(void){	return can_change_latch2;}hrtime_t pent_gettime(void){	hrtime_t t;	/* time = counter * scaler_pentium_to_hrtime / 2^32 * 2^5; */	/* Why 2^5? Because the slowest Pentiums run at 60 MHz */	__asm__("rdtsc\n\t"		"mov %%edx, %%ecx\n\t"		"mul %%ebx\n\t"  	/* multiply the low 32 bits of the counter by the scaler_pentium */		"mov %%ecx, %%eax\n\t"		"mov %%edx, %%ecx\n\t"	/* save the high 32 bits of the product */		"mul %%ebx\n\t" 	/* now the high 32 bits of the counter */		"add %%ecx, %%eax\n\t"		"adc $0, %%edx\n\t"#if HRTICKS_PER_SEC == NSECS_PER_SEC		"shld $5, %%eax, %%edx\n\t"		"shl $5, %%eax\n\t"#endif		:"=A" (t) : "b" (scaler_pentium_to_hrtime) : "cx");	return t;}/* #ifndef CONFIG_X86_TSC */extern unsigned long (*do_gettimeoffset)(void);static unsigned long (*save_do_gettimeoffset)(void);/* we can't allow Linux to read the clocks; it must use this function */#include <linux/timex.h>#define TICK_SIZE tick#define printll(x) rtl_printf("%x%08x ", (unsigned) ((x) >> 32), (unsigned) (x))static int rtl_save_jiffies;static unsigned long do_rt_gettimeoffset(void){	int count;	hrtime_t diff;	long flags;	diff = gethrtime() + LATCH_NS;	rtl_spin_lock_irqsave (&lock_linuxtime, flags);	if (/* ;rtl_global_ispending_irq(0) || */ jiffies == rtl_save_jiffies) {		diff += LATCH_NS;	}	diff -= _i8254_clock.arch.linux_time;	rtl_spin_unlock_irqrestore (&lock_linuxtime, flags);/* 	count = (((long)(now - _i8254_clock.arch.linux_time)) * TICK_SIZE) / LATCH_NS; */	count = muldiv((long)diff, TICK_SIZE, LATCH_NS);	/* 	rtl_printf("%d ", count); */	return count;}/* #endif */static void rtl_kd_nosound(unsigned long ignored){	int flags;	rtl_no_interrupts(flags);	outb(inb_p(0x61) & 0xfd, 0x61);	rtl_restore_interrupts(flags);}static void rtl_kd_mksound(unsigned int hz, unsigned int ticks){	static struct timer_list sound_timer = { function: rtl_kd_nosound };	unsigned int count = 0;	if (hz > 20 && hz < 32767)		count = 1193180 / hz;		cli();	del_timer(&sound_timer);	if (count) {		int flags;		rtl_spin_lock_irqsave (&lock8254, flags);		outb_p(inb_p(0x61)|3, 0x61);		if (can_change_latch2) {			outb_p(0xB6, 0x43);			outb_p(count & 0xff, 0x42);			outb((count >> 8) & 0xff, 0x42);		}		rtl_spin_unlock_irqrestore (&lock8254, flags);		if (ticks) {			sound_timer.expires = jiffies+ticks;			add_timer(&sound_timer);		}	} else		rtl_kd_nosound(0);	sti();	return;}static void (*save_kd_mksound)(unsigned int hz, unsigned int ticks);static void uninit_hrtime (void){	rtl_kd_mksound(0, 0);	kd_mksound = save_kd_mksound;}#define wait_value(x) do {; } while ((inb(0x61) & 0x20) != (x))#define wait_cycle() do { wait_value(0); wait_value(0x20); } while (0)#define CLATCH (1024 * 32)#define NLOOPS 50#ifdef CONFIG_X86_LOCAL_APICstatic unsigned long scaler_hrtime_to_apic;/* this is defined in arch/i386/kernel/smp.c */#define APIC_DIVISOR 16static long apic_ticks_per_sec;#endif/* scaler_pentium ==  2^32 / (2^5 * (cpu clocks per ns)) */static void do_calibration(int do_tsc){#ifdef CONFIG_X86_LOCAL_APIC	long temp = 0;	long a1 = 0;	long a2 = 0;	long save_apic = 0;	long result_apic;#endif	long long t1 = 0;	long long t2 = 0;	long pps;	int j;	long result = 0;	rtl_irqstate_t flags;	rtl_no_interrupts(flags);#ifdef CONFIG_X86_LOCAL_APIC	if (smp_found_config) {		save_apic = apic_read(APIC_TMICT);		apic_write(APIC_TMICT, 1000000000/APIC_DIVISOR);	}#endif	outb((inb(0x61) & ~0x02) | 0x01, 0x61);	outb_p(0xb6, 0x43);     /* binary, mode 3, LSB/MSB, ch 2 */	outb(CLATCH & 0xff, 0x42);	/* LSB of count */	outb(CLATCH >> 8, 0x42);	/* MSB of count */	wait_cycle();	if (do_tsc)		rdtscll(t1);#ifdef CONFIG_X86_LOCAL_APIC	if (smp_found_config) {		a1 = apic_read(APIC_TMCCT);	}#endif	for (j = 0; j < NLOOPS; j++) {		wait_cycle();/* 		rtl_allow_interrupts(); *//* 		rtl_stop_interrupts(); */	}	if (do_tsc)		rdtscll(t2);#ifdef CONFIG_X86_LOCAL_APIC	if (smp_found_config) {		a2 = apic_read(APIC_TMCCT);	}	result_apic = a1 - a2;#endif	if (do_tsc)		result = t2 - t1;#ifdef CONFIG_X86_LOCAL_APIC	if (smp_found_config) {		temp = apic_read(APIC_TMICT);		apic_write(APIC_TMICT, save_apic);	}#endif	rtl_restore_interrupts(flags);	if (do_tsc) {		pps = muldiv (result, CLOCK_TICK_RATE, CLATCH * NLOOPS);#if HRTICKS_PER_SEC == NSECS_PER_SEC		scaler_pentium_to_hrtime = muldiv (1 << 27, HRTICKS_PER_SEC, pps);#else		scaler_pentium_to_hrtime = muldiv (1 << 31, HRTICKS_PER_SEC * 2, pps);#endif	} else  {		scaler_pentium_to_hrtime = 0;	}#ifdef CONFIG_X86_LOCAL_APIC	if (smp_found_config) {		temp = muldiv (result_apic, CLOCK_TICK_RATE, CLATCH * NLOOPS);#if HRTICKS_PER_SEC == NSECS_PER_SEC		scaler_hrtime_to_apic = muldiv (temp, 1 << 31, HRTICKS_PER_SEC / 2);#else		scaler_hrtime_to_apic = muldiv (temp, 1 << (31 - 10), HRTICKS_PER_SEC / 2);#endif/* 		printk("sca=%ld, temp=%ld resapic=%ld\n", scaler_hrtime_to_apic, temp, result_apic); */ 		apic_ticks_per_sec = temp; /* 		printk("pps apic=%ld %ld\n", temp * APIC_DIVISOR, scaler_hrtime_to_apic); */	}#endif/* 	printk("pps=%ld\n", pps); */}static void init_hrtime (void){	int flags;#ifdef CONFIG_VT	kd_mksound(0, 0); /* clear the possibly pending sound timer */#endif	save_kd_mksound = kd_mksound;	kd_mksound = rtl_kd_mksound;#if HRTICKS_PER_SEC != CLOCK_TICK_RATE	scaler_8254_to_hrtime = muldiv (HRTICKS_PER_SEC, 1 << 22, CLOCK_TICK_RATE);	scaler_hrtime_to_8254 = muldiv (CLOCK_TICK_RATE, 1 << 31, HRTICKS_PER_SEC / 2);	LATCH_NS = muldiv (LATCH, HRTICKS_PER_SEC, CLOCK_TICK_RATE);#else	LATCH_NS = LATCH;#endif	MAX_LATCH_ONESHOT = LATCH_NS * 3 / 4;#ifdef CONFIG_RTL_FAST_8254	MAX_LATCH_ONESHOT = muldiv (250, HRTICKS_PER_SEC, CLOCK_TICK_RATE);#endif	rtl_no_interrupts(flags);	if (cpu_has_tsc && !notsc) {		can_change_latch2 = 1;		do_calibration(1);		rtl_do_get_time = pent_gettime;		hrtime_resolution = 32;		/* printk("scaler_pentium_to_hrtime = %d\n", (int) scaler_pentium_to_hrtime); */	} else {		do_calibration(0);		can_change_latch2 = 0;		/* program channel 2 of the 8254 chip for periodic counting */		outb_p(0xb6, 0x43);     /* binary, mode 3, LSB/MSB, ch 2 */		outb_p(LATCH2 & 0xff, 0x42);		outb_p((LATCH2 >> 8) & 0xff, 0x42);		outb_p((inb_p(0x61) & 0xfd) | 1, 0x61); /* shut up the speaker and enable counting */		LATCH_CNT2();		READ_CNT2(last_c2);		offset_time = 0;		base_time = 0;		rtl_do_get_time = global_8254_gettime;		hrtime_resolution = HRTICKS_PER_SEC / CLOCK_TICK_RATE;	}	/*	current_time.tv_sec = xtime.tv_sec;	current_time.tv_nsec = 0;	rtl_time_offset = 0;	rtl_time_offset = rtl_timespec_to_rtime(&current_time) - rtl_get_time();	*/	rtl_restore_interrupts(flags);}void rtl_clock_clear(clockid_t h){	h->uninit(h);}static hrtime_t periodic_gethrtime (struct rtl_clock *c) { return c->value; }static hrtime_t oneshot_gethrtime (struct rtl_clock *c) { return gethrtime(); }/* the 8254 clock */static unsigned int clock_counter; /* current latch value */static inline long RTIME_to_8254_ticks(long t){#if HRTICKS_PER_SEC != CLOCK_TICK_RATE	int dummy;	__asm__("mull %2"		:"=a" (dummy), "=d" (t)		:"g" (scaler_hrtime_to_8254), "0" (t)		);#endif			return (t);}void _8254_checklinuxirq (void){	/* TODO must periodically call gethrtime if it's based on i8254 */	/* or maybe not (for speed reasons)	 * anyway, here's a way to do it:	 * set a bit on every gethrtime();	 * clear it in periodic irq	 * periodically check: if it's not set, gethrtime()	 *	 * alternatively, use the fact that in periodic	 * mode we can add periods to 8254 ticks count	 */

⌨️ 快捷键说明

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