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

📄 time.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
 * Do the timer stuff. */	do_timer(regs);#ifndef CONFIG_SMP	update_process_times(user_mode(regs));#endif/* * 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	profile_tick(CPU_PROFILING, regs);#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() will be called in the jiffy * closest to exactly 500 ms before the next second. If the update fails, we * don't care, as it'll be updated on the next turn, and the problem (time way * off) isn't likely to go away much sooner anyway. */	if (ntp_synced() && xtime.tv_sec > rtc_update &&		abs(xtime.tv_nsec - 500000000) <= tick_nsec / 2) {		set_rtc_mmss(xtime.tv_sec);		rtc_update = xtime.tv_sec + 660;	} 	write_sequnlock(&xtime_lock);	return IRQ_HANDLED;}static unsigned int 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;}unsigned long long sched_clock(void){	unsigned long a = 0;#if 0	/* Don't do a HPET read here. Using TSC always is much faster	   and HPET may not be mapped yet when the scheduler first runs.           Disadvantage is a small drift between CPUs in some configurations,	   but that should be tolerable. */	if (__vxtime.mode == VXTIME_HPET)		return (hpet_readl(HPET_COUNTER) * vxtime.quot) >> 32;#endif	/* Could do CPU core sync here. Opteron can execute rdtsc speculatively,	   which means it is not completely exact and may not be monotonous between	   CPUs. But the errors should be too small to matter for scheduling	   purposes. */	rdtscll(a);	return cycles_2_ns(a);}unsigned long get_cmos_time(void){	unsigned int timeout, year, mon, day, hour, min, sec;	unsigned char last, this;	unsigned long flags;/* * 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. Waiting for this can take up to 1 * second, we timeout approximately after 2.4 seconds on a machine with * standard 8.3 MHz ISA bus. */	spin_lock_irqsave(&rtc_lock, flags);	timeout = 1000000;	last = this = 0;	while (timeout && last && !this) {		last = this;		this = CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP;		timeout--;	}/* * Here we are safe to assume the registers won't change for a whole second, so * we just go ahead and read them.	 */		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);	spin_unlock_irqrestore(&rtc_lock, flags);/* * We know that x86-64 always uses BCD format, no need to check the config * register. */	    BCD_TO_BIN(sec);	    BCD_TO_BIN(min);	    BCD_TO_BIN(hour);	    BCD_TO_BIN(day);	    BCD_TO_BIN(mon);	    BCD_TO_BIN(year);/* * x86-64 systems only exists since 2002. * This will work up to Dec 31, 2100 */	year += 2000;	return mktime(year, mon, day, hour, min, sec);}#ifdef CONFIG_CPU_FREQ/* Frequency scaling support. Adjust the TSC based timer when the cpu frequency   changes.      RED-PEN: On SMP we assume all CPUs run with the same frequency.  It's   not that important because current Opteron setups do not support   scaling on SMP anyroads.   Should fix up last_tsc too. Currently gettimeofday in the   first tick after the change will be slightly wrong. */#include <linux/workqueue.h>static unsigned int cpufreq_delayed_issched = 0;static unsigned int cpufreq_init = 0;static struct work_struct cpufreq_delayed_get_work;static void handle_cpufreq_delayed_get(void *v){	unsigned int cpu;	for_each_online_cpu(cpu) {		cpufreq_get(cpu);	}	cpufreq_delayed_issched = 0;}/* if we notice lost ticks, schedule a call to cpufreq_get() as it tries * to verify the CPU frequency the timing core thinks the CPU is running * at is still correct. */static void cpufreq_delayed_get(void){	static int warned;	if (cpufreq_init && !cpufreq_delayed_issched) {		cpufreq_delayed_issched = 1;		if (!warned) {			warned = 1;			printk(KERN_DEBUG "Losing some ticks... checking if CPU frequency changed.\n");		}		schedule_work(&cpufreq_delayed_get_work);	}}static unsigned int  ref_freq = 0;static unsigned long loops_per_jiffy_ref = 0;static unsigned long cpu_khz_ref = 0;static int time_cpufreq_notifier(struct notifier_block *nb, unsigned long val,				 void *data){        struct cpufreq_freqs *freq = data;	unsigned long *lpj, dummy;	if (cpu_has(&cpu_data[freq->cpu], X86_FEATURE_CONSTANT_TSC))		return 0;	lpj = &dummy;	if (!(freq->flags & CPUFREQ_CONST_LOOPS))#ifdef CONFIG_SMP	lpj = &cpu_data[freq->cpu].loops_per_jiffy;#else	lpj = &boot_cpu_data.loops_per_jiffy;#endif	if (!ref_freq) {		ref_freq = freq->old;		loops_per_jiffy_ref = *lpj;		cpu_khz_ref = cpu_khz;	}        if ((val == CPUFREQ_PRECHANGE  && freq->old < freq->new) ||            (val == CPUFREQ_POSTCHANGE && freq->old > freq->new) ||	    (val == CPUFREQ_RESUMECHANGE)) {                *lpj =		cpufreq_scale(loops_per_jiffy_ref, ref_freq, freq->new);		cpu_khz = cpufreq_scale(cpu_khz_ref, ref_freq, freq->new);		if (!(freq->flags & CPUFREQ_CONST_LOOPS))			vxtime.tsc_quot = (1000L << 32) / cpu_khz;	}		set_cyc2ns_scale(cpu_khz_ref);	return 0;} static struct notifier_block time_cpufreq_notifier_block = {         .notifier_call  = time_cpufreq_notifier};static int __init cpufreq_tsc(void){	INIT_WORK(&cpufreq_delayed_get_work, handle_cpufreq_delayed_get, NULL);	if (!cpufreq_register_notifier(&time_cpufreq_notifier_block,				       CPUFREQ_TRANSITION_NOTIFIER))		cpufreq_init = 1;	return 0;}core_initcall(cpufreq_tsc);#endif/* * calibrate_tsc() calibrates the processor TSC in a very simple way, comparing * it to the HPET timer of known frequency. */#define TICK_COUNT 100000000static unsigned int __init hpet_calibrate_tsc(void){	int tsc_start, hpet_start;	int tsc_now, hpet_now;	unsigned long flags;	local_irq_save(flags);	local_irq_disable();	hpet_start = hpet_readl(HPET_COUNTER);	rdtscl(tsc_start);	do {		local_irq_disable();		hpet_now = hpet_readl(HPET_COUNTER);		sync_core();		rdtscl(tsc_now);		local_irq_restore(flags);	} while ((tsc_now - tsc_start) < TICK_COUNT &&		 (hpet_now - hpet_start) < TICK_COUNT);	return (tsc_now - tsc_start) * 1000000000L		/ ((hpet_now - hpet_start) * hpet_period / 1000);}/* * pit_calibrate_tsc() uses the speaker output (channel 2) of * the PIT. This is better than using the timer interrupt output, * because we can read the value of the speaker with just one inb(), * where we need three i/o operations for the interrupt channel. * We count how many ticks the TSC does in 50 ms. */static unsigned int __init pit_calibrate_tsc(void){	unsigned long start, end;	unsigned long flags;	spin_lock_irqsave(&i8253_lock, flags);	outb((inb(0x61) & ~0x02) | 0x01, 0x61);	outb(0xb0, 0x43);	outb((PIT_TICK_RATE / (1000 / 50)) & 0xff, 0x42);	outb((PIT_TICK_RATE / (1000 / 50)) >> 8, 0x42);	rdtscll(start);	sync_core();	while ((inb(0x61) & 0x20) == 0);	sync_core();	rdtscll(end);	spin_unlock_irqrestore(&i8253_lock, flags);		return (end - start) / 50;}#ifdef	CONFIG_HPETstatic __init int late_hpet_init(void){	struct hpet_data	hd;	unsigned int 		ntimer;	if (!vxtime.hpet_address)          return -1;	memset(&hd, 0, sizeof (hd));	ntimer = hpet_readl(HPET_ID);	ntimer = (ntimer & HPET_ID_NUMBER) >> HPET_ID_NUMBER_SHIFT;	ntimer++;	/*	 * Register with driver.	 * Timer0 and Timer1 is used by platform.	 */	hd.hd_phys_address = vxtime.hpet_address;	hd.hd_address = (void *)fix_to_virt(FIX_HPET_BASE);	hd.hd_nirqs = ntimer;	hd.hd_flags = HPET_DATA_PLATFORM;	hpet_reserve_timer(&hd, 0);#ifdef	CONFIG_HPET_EMULATE_RTC	hpet_reserve_timer(&hd, 1);#endif	hd.hd_irq[0] = HPET_LEGACY_8254;	hd.hd_irq[1] = HPET_LEGACY_RTC;	if (ntimer > 2) {		struct hpet		*hpet;		struct hpet_timer	*timer;		int			i;		hpet = (struct hpet *) fix_to_virt(FIX_HPET_BASE);		for (i = 2, timer = &hpet->hpet_timers[2]; i < ntimer;		     timer++, i++)			hd.hd_irq[i] = (timer->hpet_config &					Tn_INT_ROUTE_CNF_MASK) >>				Tn_INT_ROUTE_CNF_SHIFT;	}	hpet_alloc(&hd);	return 0;}fs_initcall(late_hpet_init);#endifstatic int hpet_timer_stop_set_go(unsigned long tick){	unsigned int cfg;/* * Stop the timers and reset the main counter. */	cfg = hpet_readl(HPET_CFG);	cfg &= ~(HPET_CFG_ENABLE | HPET_CFG_LEGACY);	hpet_writel(cfg, HPET_CFG);	hpet_writel(0, HPET_COUNTER);	hpet_writel(0, HPET_COUNTER + 4);/* * Set up timer 0, as periodic with first interrupt to happen at hpet_tick, * and period also hpet_tick. */	if (hpet_use_timer) {		hpet_writel(HPET_TN_ENABLE | HPET_TN_PERIODIC | HPET_TN_SETVAL |		    HPET_TN_32BIT, HPET_T0_CFG);		hpet_writel(hpet_tick, HPET_T0_CMP);		hpet_writel(hpet_tick, HPET_T0_CMP); /* AK: why twice? */		cfg |= HPET_CFG_LEGACY;	}/* * Go! */	cfg |= HPET_CFG_ENABLE;	hpet_writel(cfg, HPET_CFG);	return 0;}static int hpet_init(void){	unsigned int id;	if (!vxtime.hpet_address)		return -1;	set_fixmap_nocache(FIX_HPET_BASE, vxtime.hpet_address);	__set_fixmap(VSYSCALL_HPET, vxtime.hpet_address, PAGE_KERNEL_VSYSCALL_NOCACHE);/* * Read the period, compute tick and quotient. */	id = hpet_readl(HPET_ID);	if (!(id & HPET_ID_VENDOR) || !(id & HPET_ID_NUMBER))		return -1;	hpet_period = hpet_readl(HPET_PERIOD);	if (hpet_period < 100000 || hpet_period > 100000000)		return -1;	hpet_tick = (1000000000L * (USEC_PER_SEC / HZ) + hpet_period / 2) /		hpet_period;	hpet_use_timer = (id & HPET_ID_LEGSUP);	return hpet_timer_stop_set_go(hpet_tick);}static int hpet_reenable(void){	return hpet_timer_stop_set_go(hpet_tick);}void __init pit_init(void){	unsigned long flags;	spin_lock_irqsave(&i8253_lock, flags);	outb_p(0x34, 0x43);		/* binary, mode 2, LSB/MSB, ch 0 */	outb_p(LATCH & 0xff, 0x40);	/* LSB */	outb_p(LATCH >> 8, 0x40);	/* MSB */	spin_unlock_irqrestore(&i8253_lock, flags);}int __init time_setup(char *str){

⌨️ 快捷键说明

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