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

📄 time.c

📁 是关于linux2.5.1的完全源码
💻 C
📖 第 1 页 / 共 2 页
字号:
		 */		spin_lock(&i8259A_lock);		outb(0x0c, 0x20);		/* Ack the IRQ; AEOI will end it automatically. */		inb(0x20);		spin_unlock(&i8259A_lock);	}#endif	do_timer(regs);/* * In the SMP case we use the local APIC timer interrupt to do the * profiling, except when we simulate SMP mode on a uniprocessor * system, in that case we have to call the local interrupt handler. */#ifndef CONFIG_X86_LOCAL_APIC	if (!user_mode(regs))		x86_do_profile(regs->rip);#else	if (!using_apic_timer)		smp_local_timer_interrupt(regs);#endif	/*	 * If we have an externally synchronized Linux clock, then update	 * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be	 * called as close as possible to 500 ms before the new second starts.	 */	if ((time_status & STA_UNSYNC) == 0 &&	    xtime.tv_sec > last_rtc_update + 660 &&	    xtime.tv_usec >= 500000 - ((unsigned) tick) / 2 &&	    xtime.tv_usec <= 500000 + ((unsigned) tick) / 2) {		if (set_rtc_mmss(xtime.tv_sec) == 0)			last_rtc_update = xtime.tv_sec;		else			last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */	}}static int use_tsc;/* * This is the same as the above, except we _also_ save the current * Time Stamp Counter value at the time of the timer interrupt, so that * we later on can estimate the time of day more exactly. */static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs){	int count;	/*	 * Here we are in the timer irq handler. We just have irqs locally	 * disabled but we don't know if the timer_bh is running on the other	 * CPU. We need to avoid to SMP race with it. NOTE: we don' t need	 * the irq version of write_lock because as just said we have irq	 * locally disabled. -arca	 */	write_lock(&xtime_lock);	vxtime_lock();	if (use_tsc)	{		/*		 * It is important that these two operations happen almost at		 * the same time. We do the RDTSC stuff first, since it's		 * faster. To avoid any inconsistencies, we need interrupts		 * disabled locally.		 */		/*		 * Interrupts are just disabled locally since the timer irq		 * has the SA_INTERRUPT flag set. -arca		 */			/* read Pentium cycle counter */		rdtscl(last_tsc_low);		spin_lock(&i8253_lock);		outb_p(0x00, 0x43);     /* latch the count ASAP */		count = inb_p(0x40);    /* read the latched count */		count |= inb(0x40) << 8;		spin_unlock(&i8253_lock);		count = ((LATCH-1) - count) * TICK_SIZE;		delay_at_last_interrupt = (count + LATCH/2) / LATCH;	} 	do_timer_interrupt(irq, NULL, regs);	vxtime_unlock();	write_unlock(&xtime_lock);}/* not static: needed by APM */unsigned long get_cmos_time(void){	unsigned int year, mon, day, hour, min, sec;	int i;	spin_lock(&rtc_lock); 	/* The Linux interpretation of the CMOS clock register contents:	 * When the Update-In-Progress (UIP) flag goes from 1 to 0, the	 * RTC registers show the second which has precisely just started.	 * Let's hope other operating systems interpret the RTC the same way.	 */	/* read RTC exactly on falling edge of update flag */	for (i = 0 ; i < 1000000 ; i++)	/* may take up to 1 second... */		if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)			break;	for (i = 0 ; i < 1000000 ; i++)	/* must try at least 2.228 ms */		if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))			break;	do { /* Isn't this overkill ? UIP above should guarantee consistency */		sec = CMOS_READ(RTC_SECONDS);		min = CMOS_READ(RTC_MINUTES);		hour = CMOS_READ(RTC_HOURS);		day = CMOS_READ(RTC_DAY_OF_MONTH);		mon = CMOS_READ(RTC_MONTH);		year = CMOS_READ(RTC_YEAR);	} while (sec != CMOS_READ(RTC_SECONDS));	if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)	  {	    BCD_TO_BIN(sec);	    BCD_TO_BIN(min);	    BCD_TO_BIN(hour);	    BCD_TO_BIN(day);	    BCD_TO_BIN(mon);	    BCD_TO_BIN(year);	  }	spin_unlock(&rtc_lock); 	if ((year += 1900) < 1970)		year += 100;	return mktime(year, mon, day, hour, min, sec);}static struct irqaction irq0  = { timer_interrupt, SA_INTERRUPT, 0, "timer", NULL, NULL};/* ------ Calibrate the TSC -------  * Return 2^32 * (1 / (TSC clocks per usec)) for do_fast_gettimeoffset(). * Too much 64-bit arithmetic here to do this cleanly in C, and for * accuracy's sake we want to keep the overhead on the CTC speaker (channel 2) * output busy loop as low as possible. We avoid reading the CTC registers * directly because of the awkward 8-bit access mechanism of the 82C54 * device. */#define CALIBRATE_LATCH	(5 * LATCH)#define CALIBRATE_TIME	(5 * 1000020/HZ)/* Could use 64bit arithmetic on x86-64, but the code is too fragile */static unsigned long __init calibrate_tsc(void){       /* Set the Gate high, disable speaker */	outb((inb(0x61) & ~0x02) | 0x01, 0x61);	/*	 * Now let's take care of CTC channel 2	 *	 * Set the Gate high, program CTC channel 2 for mode 0,	 * (interrupt on terminal count mode), binary count,	 * load 5 * LATCH count, (LSB and MSB) to begin countdown.	 */	outb(0xb0, 0x43);			/* binary, mode 0, LSB/MSB, Ch 2 */	outb(CALIBRATE_LATCH & 0xff, 0x42);	/* LSB of count */	outb(CALIBRATE_LATCH >> 8, 0x42);	/* MSB of count */	{		unsigned int startlow, starthigh;		unsigned int endlow, endhigh;		unsigned int count;		rdtsc(startlow,starthigh);		count = 0;		do {			count++;		} while ((inb(0x61) & 0x20) == 0);		rdtsc(endlow,endhigh);		last_tsc_low = endlow; 		/* Error: ECTCNEVERSET */		if (count <= 1)			goto bad_ctc;		__asm__("subl %2,%0\n\t"			"sbbl %3,%1"			:"=a" (endlow), "=d" (endhigh)			:"g" (startlow), "g" (starthigh),			 "0" (endlow), "1" (endhigh));		/* Error: ECPUTOOFAST */		if (endhigh)			goto bad_ctc;		/* Error: ECPUTOOSLOW */		if (endlow  <= CALIBRATE_TIME)			goto bad_ctc;		__asm__("divl %2"			:"=a" (endlow), "=d" (endhigh)			:"r" (endlow), "0" (0), "1" (CALIBRATE_TIME));      			return endlow;	}	/*	 * The CTC wasn't reliable: we got a hit on the very first read,	 * or the CPU was so fast/slow that the quotient wouldn't fit in	 * 32 bits..	 */bad_ctc:	return 0;}void __init time_init(void){	extern int x86_udelay_tsc;		xtime.tv_sec = get_cmos_time();	xtime.tv_usec = 0;/* * If we have APM enabled or the CPU clock speed is variable * (CPU stops clock on HLT or slows clock to save power) * then the TSC timestamps may diverge by up to 1 jiffy from * 'real time' but nothing will break. * The most frequent case is that the CPU is "woken" from a halt * state by the timer interrupt itself, so we get 0 error. In the * rare cases where a driver would "wake" the CPU and request a * timestamp, the maximum error is < 1 jiffy. But timestamps are * still perfectly ordered. */	if (cpu_has_tsc) {		unsigned int tsc_quotient = calibrate_tsc();		if (tsc_quotient) {			fast_gettimeoffset_quotient = tsc_quotient;			use_tsc = 1;			/*			 *	We could be more selective here I suspect			 *	and just enable this for the next intel chips ?			 */			x86_udelay_tsc = 1;			/* 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 int eax=0, edx=1000;				__asm__("divl %2"		       		:"=a" (cpu_khz), "=d" (edx)        	       		:"r" (tsc_quotient),	                	"0" (eax), "1" (edx));				printk("Detected %u.%03u MHz processor.\n", 				       cpu_khz / 1000, cpu_khz % 1000);			}		}	}	setup_irq(0, &irq0);}

⌨️ 快捷键说明

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