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

📄 time.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 3 页
字号:
	report_lost_ticks = 1;	return 1;}static struct irqaction irq0 = {	timer_interrupt, SA_INTERRUPT, CPU_MASK_NONE, "timer", NULL, NULL};extern void __init config_acpi_tables(void);void __init time_init(void){	char *timename;#ifdef HPET_HACK_ENABLE_DANGEROUS        if (!vxtime.hpet_address) {		printk(KERN_WARNING "time.c: WARNING: Enabling HPET base "		       "manually!\n");                outl(0x800038a0, 0xcf8);                outl(0xff000001, 0xcfc);                outl(0x800038a0, 0xcf8);                vxtime.hpet_address = inl(0xcfc) & 0xfffffffe;		printk(KERN_WARNING "time.c: WARNING: Enabled HPET "		       "at %#lx.\n", vxtime.hpet_address);        }#endif	if (nohpet)		vxtime.hpet_address = 0;	xtime.tv_sec = get_cmos_time();	xtime.tv_nsec = 0;	set_normalized_timespec(&wall_to_monotonic,	                        -xtime.tv_sec, -xtime.tv_nsec);	if (!hpet_init())                vxtime_hz = (1000000000000000L + hpet_period / 2) /			hpet_period;	else		vxtime.hpet_address = 0;	if (hpet_use_timer) {		cpu_khz = hpet_calibrate_tsc();		timename = "HPET";#ifdef CONFIG_X86_PM_TIMER	} else if (pmtmr_ioport && !vxtime.hpet_address) {		vxtime_hz = PM_TIMER_FREQUENCY;		timename = "PM";		pit_init();		cpu_khz = pit_calibrate_tsc();#endif	} else {		pit_init();		cpu_khz = pit_calibrate_tsc();		timename = "PIT";	}	printk(KERN_INFO "time.c: Using %ld.%06ld MHz %s timer.\n",	       vxtime_hz / 1000000, vxtime_hz % 1000000, timename);	printk(KERN_INFO "time.c: Detected %d.%03d MHz processor.\n",		cpu_khz / 1000, cpu_khz % 1000);	vxtime.mode = VXTIME_TSC;	vxtime.quot = (1000000L << 32) / vxtime_hz;	vxtime.tsc_quot = (1000L << 32) / cpu_khz;	rdtscll_sync(&vxtime.last_tsc);	setup_irq(0, &irq0);	set_cyc2ns_scale(cpu_khz);#ifndef CONFIG_SMP	time_init_gtod();#endif}/* * Make an educated guess if the TSC is trustworthy and synchronized * over all CPUs. */static __init int unsynchronized_tsc(void){#ifdef CONFIG_SMP	if (oem_force_hpet_timer())		return 1; 	/* Intel systems are normally all synchronized. Exceptions 	   are handled in the OEM check above. */ 	if (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL) 		return 0;#endif 	/* Assume multi socket systems are not synchronized */ 	return num_online_cpus() > 1;}/* * Decide after all CPUs are booted what mode gettimeofday should use. */void __init time_init_gtod(void){	char *timetype;	if (unsynchronized_tsc())		notsc = 1;	if (vxtime.hpet_address && notsc) {		timetype = hpet_use_timer ? "HPET" : "PIT/HPET";		vxtime.last = hpet_readl(HPET_T0_CMP) - hpet_tick;		vxtime.mode = VXTIME_HPET;		do_gettimeoffset = do_gettimeoffset_hpet;#ifdef CONFIG_X86_PM_TIMER	/* Using PM for gettimeofday is quite slow, but we have no other	   choice because the TSC is too unreliable on some systems. */	} else if (pmtmr_ioport && !vxtime.hpet_address && notsc) {		timetype = "PM";		do_gettimeoffset = do_gettimeoffset_pm;		vxtime.mode = VXTIME_PMTMR;		sysctl_vsyscall = 0;		printk(KERN_INFO "Disabling vsyscall due to use of PM timer\n");#endif	} else {		timetype = hpet_use_timer ? "HPET/TSC" : "PIT/TSC";		vxtime.mode = VXTIME_TSC;	}	printk(KERN_INFO "time.c: Using %s based timekeeping.\n", timetype);}__setup("report_lost_ticks", time_setup);static long clock_cmos_diff;static unsigned long sleep_start;static int timer_suspend(struct sys_device *dev, pm_message_t state){	/*	 * Estimate time zone so that set_time can update the clock	 */	long cmos_time =  get_cmos_time();	clock_cmos_diff = -cmos_time;	clock_cmos_diff += get_seconds();	sleep_start = cmos_time;	return 0;}static int timer_resume(struct sys_device *dev){	unsigned long flags;	unsigned long sec;	unsigned long ctime = get_cmos_time();	unsigned long sleep_length = (ctime - sleep_start) * HZ;	if (vxtime.hpet_address)		hpet_reenable();	else		i8254_timer_resume();	sec = ctime + clock_cmos_diff;	write_seqlock_irqsave(&xtime_lock,flags);	xtime.tv_sec = sec;	xtime.tv_nsec = 0;	write_sequnlock_irqrestore(&xtime_lock,flags);	jiffies += sleep_length;	wall_jiffies += sleep_length;	touch_softlockup_watchdog();	return 0;}static struct sysdev_class timer_sysclass = {	.resume = timer_resume,	.suspend = timer_suspend,	set_kset_name("timer"),};/* XXX this driverfs stuff should probably go elsewhere later -john */static struct sys_device device_timer = {	.id	= 0,	.cls	= &timer_sysclass,};static int time_init_device(void){	int error = sysdev_class_register(&timer_sysclass);	if (!error)		error = sysdev_register(&device_timer);	return error;}device_initcall(time_init_device);#ifdef CONFIG_HPET_EMULATE_RTC/* HPET in LegacyReplacement Mode eats up RTC interrupt line. When, HPET * is enabled, we support RTC interrupt functionality in software. * RTC has 3 kinds of interrupts: * 1) Update Interrupt - generate an interrupt, every sec, when RTC clock *    is updated * 2) Alarm Interrupt - generate an interrupt at a specific time of day * 3) Periodic Interrupt - generate periodic interrupt, with frequencies *    2Hz-8192Hz (2Hz-64Hz for non-root user) (all freqs in powers of 2) * (1) and (2) above are implemented using polling at a frequency of * 64 Hz. The exact frequency is a tradeoff between accuracy and interrupt * overhead. (DEFAULT_RTC_INT_FREQ) * For (3), we use interrupts at 64Hz or user specified periodic * frequency, whichever is higher. */#include <linux/rtc.h>extern irqreturn_t rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs);#define DEFAULT_RTC_INT_FREQ 	64#define RTC_NUM_INTS 		1static unsigned long UIE_on;static unsigned long prev_update_sec;static unsigned long AIE_on;static struct rtc_time alarm_time;static unsigned long PIE_on;static unsigned long PIE_freq = DEFAULT_RTC_INT_FREQ;static unsigned long PIE_count;static unsigned long hpet_rtc_int_freq; /* RTC interrupt frequency */static unsigned int hpet_t1_cmp; /* cached comparator register */int is_hpet_enabled(void){	return vxtime.hpet_address != 0;}/* * Timer 1 for RTC, we do not use periodic interrupt feature, * even if HPET supports periodic interrupts on Timer 1. * The reason being, to set up a periodic interrupt in HPET, we need to * stop the main counter. And if we do that everytime someone diables/enables * RTC, we will have adverse effect on main kernel timer running on Timer 0. * So, for the time being, simulate the periodic interrupt in software. * * hpet_rtc_timer_init() is called for the first time and during subsequent * interuppts reinit happens through hpet_rtc_timer_reinit(). */int hpet_rtc_timer_init(void){	unsigned int cfg, cnt;	unsigned long flags;	if (!is_hpet_enabled())		return 0;	/*	 * Set the counter 1 and enable the interrupts.	 */	if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))		hpet_rtc_int_freq = PIE_freq;	else		hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;	local_irq_save(flags);	cnt = hpet_readl(HPET_COUNTER);	cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);	hpet_writel(cnt, HPET_T1_CMP);	hpet_t1_cmp = cnt;	local_irq_restore(flags);	cfg = hpet_readl(HPET_T1_CFG);	cfg &= ~HPET_TN_PERIODIC;	cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;	hpet_writel(cfg, HPET_T1_CFG);	return 1;}static void hpet_rtc_timer_reinit(void){	unsigned int cfg, cnt;	if (unlikely(!(PIE_on | AIE_on | UIE_on))) {		cfg = hpet_readl(HPET_T1_CFG);		cfg &= ~HPET_TN_ENABLE;		hpet_writel(cfg, HPET_T1_CFG);		return;	}	if (PIE_on && (PIE_freq > DEFAULT_RTC_INT_FREQ))		hpet_rtc_int_freq = PIE_freq;	else		hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;	/* It is more accurate to use the comparator value than current count.*/	cnt = hpet_t1_cmp;	cnt += hpet_tick*HZ/hpet_rtc_int_freq;	hpet_writel(cnt, HPET_T1_CMP);	hpet_t1_cmp = cnt;}/* * The functions below are called from rtc driver. * Return 0 if HPET is not being used. * Otherwise do the necessary changes and return 1. */int hpet_mask_rtc_irq_bit(unsigned long bit_mask){	if (!is_hpet_enabled())		return 0;	if (bit_mask & RTC_UIE)		UIE_on = 0;	if (bit_mask & RTC_PIE)		PIE_on = 0;	if (bit_mask & RTC_AIE)		AIE_on = 0;	return 1;}int hpet_set_rtc_irq_bit(unsigned long bit_mask){	int timer_init_reqd = 0;	if (!is_hpet_enabled())		return 0;	if (!(PIE_on | AIE_on | UIE_on))		timer_init_reqd = 1;	if (bit_mask & RTC_UIE) {		UIE_on = 1;	}	if (bit_mask & RTC_PIE) {		PIE_on = 1;		PIE_count = 0;	}	if (bit_mask & RTC_AIE) {		AIE_on = 1;	}	if (timer_init_reqd)		hpet_rtc_timer_init();	return 1;}int hpet_set_alarm_time(unsigned char hrs, unsigned char min, unsigned char sec){	if (!is_hpet_enabled())		return 0;	alarm_time.tm_hour = hrs;	alarm_time.tm_min = min;	alarm_time.tm_sec = sec;	return 1;}int hpet_set_periodic_freq(unsigned long freq){	if (!is_hpet_enabled())		return 0;	PIE_freq = freq;	PIE_count = 0;	return 1;}int hpet_rtc_dropped_irq(void){	if (!is_hpet_enabled())		return 0;	return 1;}irqreturn_t hpet_rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct rtc_time curr_time;	unsigned long rtc_int_flag = 0;	int call_rtc_interrupt = 0;	hpet_rtc_timer_reinit();	if (UIE_on | AIE_on) {		rtc_get_rtc_time(&curr_time);	}	if (UIE_on) {		if (curr_time.tm_sec != prev_update_sec) {			/* Set update int info, call real rtc int routine */			call_rtc_interrupt = 1;			rtc_int_flag = RTC_UF;			prev_update_sec = curr_time.tm_sec;		}	}	if (PIE_on) {		PIE_count++;		if (PIE_count >= hpet_rtc_int_freq/PIE_freq) {			/* Set periodic int info, call real rtc int routine */			call_rtc_interrupt = 1;			rtc_int_flag |= RTC_PF;			PIE_count = 0;		}	}	if (AIE_on) {		if ((curr_time.tm_sec == alarm_time.tm_sec) &&		    (curr_time.tm_min == alarm_time.tm_min) &&		    (curr_time.tm_hour == alarm_time.tm_hour)) {			/* Set alarm int info, call real rtc int routine */			call_rtc_interrupt = 1;			rtc_int_flag |= RTC_AF;		}	}	if (call_rtc_interrupt) {		rtc_int_flag |= (RTC_IRQF | (RTC_NUM_INTS << 8));		rtc_interrupt(rtc_int_flag, dev_id, regs);	}	return IRQ_HANDLED;}#endifstatic int __init nohpet_setup(char *s) { 	nohpet = 1;	return 0;} __setup("nohpet", nohpet_setup);static int __init notsc_setup(char *s){	notsc = 1;	return 0;}__setup("notsc", notsc_setup);

⌨️ 快捷键说明

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