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

📄 time.c

📁 该文件是rt_linux
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: time.c,v 1.41.2.2 2002/03/03 04:08:10 davem Exp $ * time.c: UltraSparc timer and TOD clock support. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) * Copyright (C) 1998 Eddie C. Dost   (ecd@skynet.be) * * Based largely on code which is: * * Copyright (C) 1996 Thomas K. Dyas (tdyas@eden.rutgers.edu) */#include <linux/config.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/kernel.h>#include <linux/param.h>#include <linux/string.h>#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/timex.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/mc146818rtc.h>#include <linux/delay.h>#include <asm/oplib.h>#include <asm/mostek.h>#include <asm/timer.h>#include <asm/irq.h>#include <asm/io.h>#include <asm/sbus.h>#include <asm/fhc.h>#include <asm/pbm.h>#include <asm/ebus.h>#include <asm/isa.h>#include <asm/starfire.h>extern rwlock_t xtime_lock;spinlock_t mostek_lock = SPIN_LOCK_UNLOCKED;spinlock_t rtc_lock = SPIN_LOCK_UNLOCKED;unsigned long mstk48t02_regs = 0UL;#ifdef CONFIG_PCIunsigned long ds1287_regs = 0UL;#endifstatic unsigned long mstk48t08_regs = 0UL;static unsigned long mstk48t59_regs = 0UL;static int set_rtc_mmss(unsigned long);/* timer_interrupt() needs to keep up the real-time clock, * as well as call the "do_timer()" routine every clocktick * * NOTE: On SUN5 systems the ticker interrupt comes in using 2 *       interrupts, one at level14 and one with softint bit 0. */unsigned long timer_tick_offset;unsigned long timer_tick_compare;unsigned long timer_ticks_per_usec_quotient;static __inline__ void timer_check_rtc(void){	/* last time the cmos clock got updated */	static long last_rtc_update;	/* Determine when to update the Mostek clock. */	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 */	}}void sparc64_do_profile(unsigned long pc, unsigned long o7){	if (prof_buffer && current->pid) {		extern int _stext;		extern int rwlock_impl_begin, rwlock_impl_end;		extern int atomic_impl_begin, atomic_impl_end;		extern int __memcpy_begin, __memcpy_end;		extern int __bzero_begin, __bzero_end;		extern int __bitops_begin, __bitops_end;		if ((pc >= (unsigned long) &atomic_impl_begin &&		     pc < (unsigned long) &atomic_impl_end) ||		    (pc >= (unsigned long) &rwlock_impl_begin &&		     pc < (unsigned long) &rwlock_impl_end) ||		    (pc >= (unsigned long) &__memcpy_begin &&		     pc < (unsigned long) &__memcpy_end) ||		    (pc >= (unsigned long) &__bzero_begin &&		     pc < (unsigned long) &__bzero_end) ||		    (pc >= (unsigned long) &__bitops_begin &&		     pc < (unsigned long) &__bitops_end))			pc = o7;		pc -= (unsigned long) &_stext;		pc >>= prof_shift;		if(pc >= prof_len)			pc = prof_len - 1;		atomic_inc((atomic_t *)&prof_buffer[pc]);	}}static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs){	unsigned long ticks, pstate;	write_lock(&xtime_lock);	do {#ifndef CONFIG_SMP		if ((regs->tstate & TSTATE_PRIV) != 0)			sparc64_do_profile(regs->tpc, regs->u_regs[UREG_RETPC]);#endif		do_timer(regs);		/* Guarentee that the following sequences execute		 * uninterrupted.		 */		__asm__ __volatile__("rdpr	%%pstate, %0\n\t"				     "wrpr	%0, %1, %%pstate"				     : "=r" (pstate)				     : "i" (PSTATE_IE));		/* Workaround for Spitfire Errata (#54 I think??), I discovered		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch		 * number 103640.		 *		 * On Blackbird writes to %tick_cmpr can fail, the		 * workaround seems to be to execute the wr instruction		 * at the start of an I-cache line, and perform a dummy		 * read back from %tick_cmpr right after writing to it. -DaveM		 *		 * Just to be anal we add a workaround for Spitfire		 * Errata 50 by preventing pipeline bypasses on the		 * final read of the %tick register into a compare		 * instruction.  The Errata 50 description states		 * that %tick is not prone to this bug, but I am not		 * taking any chances.		 */		if (!SPARC64_USE_STICK) {		__asm__ __volatile__(		"	rd	%%tick_cmpr, %0\n"		"	ba,pt	%%xcc, 1f\n"		"	 add	%0, %2, %0\n"		"	.align	64\n"		"1: 	wr	%0, 0, %%tick_cmpr\n"		"	rd	%%tick_cmpr, %%g0\n"		"	rd	%%tick, %1\n"		"	mov	%1, %1"			: "=&r" (timer_tick_compare), "=r" (ticks)			: "r" (timer_tick_offset));		} else {		__asm__ __volatile__(		"	rd	%%asr25, %0\n"		"	add	%0, %2, %0\n"		"	wr	%0, 0, %%asr25\n"		"	rd	%%asr24, %1"			: "=&r" (timer_tick_compare), "=r" (ticks)			: "r" (timer_tick_offset));		}		/* Restore PSTATE_IE. */		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"				     : /* no outputs */				     : "r" (pstate));	} while (ticks >= timer_tick_compare);	timer_check_rtc();	write_unlock(&xtime_lock);}#ifdef CONFIG_SMPvoid timer_tick_interrupt(struct pt_regs *regs){	write_lock(&xtime_lock);	do_timer(regs);	/*	 * Only keep timer_tick_offset uptodate, but don't set TICK_CMPR.	 */	if (!SPARC64_USE_STICK) {	__asm__ __volatile__(	"	rd	%%tick_cmpr, %0\n"	"	add	%0, %1, %0"		: "=&r" (timer_tick_compare)		: "r" (timer_tick_offset));	} else {	__asm__ __volatile__(	"	rd	%%asr25, %0\n"	"	add	%0, %1, %0"		: "=&r" (timer_tick_compare)		: "r" (timer_tick_offset));	}	timer_check_rtc();	write_unlock(&xtime_lock);}#endif/* Kick start a stopped clock (procedure from the Sun NVRAM/hostid FAQ). */static void __init kick_start_clock(void){	unsigned long regs = mstk48t02_regs;	u8 sec, tmp;	int i, count;	prom_printf("CLOCK: Clock was stopped. Kick start ");	spin_lock_irq(&mostek_lock);	/* Turn on the kick start bit to start the oscillator. */	tmp = mostek_read(regs + MOSTEK_CREG);	tmp |= MSTK_CREG_WRITE;	mostek_write(regs + MOSTEK_CREG, tmp);	tmp = mostek_read(regs + MOSTEK_SEC);	tmp &= ~MSTK_STOP;	mostek_write(regs + MOSTEK_SEC, tmp);	tmp = mostek_read(regs + MOSTEK_HOUR);	tmp |= MSTK_KICK_START;	mostek_write(regs + MOSTEK_HOUR, tmp);	tmp = mostek_read(regs + MOSTEK_CREG);	tmp &= ~MSTK_CREG_WRITE;	mostek_write(regs + MOSTEK_CREG, tmp);	spin_unlock_irq(&mostek_lock);	/* Delay to allow the clock oscillator to start. */	sec = MSTK_REG_SEC(regs);	for (i = 0; i < 3; i++) {		while (sec == MSTK_REG_SEC(regs))			for (count = 0; count < 100000; count++)				/* nothing */ ;		prom_printf(".");		sec = MSTK_REG_SEC(regs);	}	prom_printf("\n");	spin_lock_irq(&mostek_lock);	/* Turn off kick start and set a "valid" time and date. */	tmp = mostek_read(regs + MOSTEK_CREG);	tmp |= MSTK_CREG_WRITE;	mostek_write(regs + MOSTEK_CREG, tmp);	tmp = mostek_read(regs + MOSTEK_HOUR);	tmp &= ~MSTK_KICK_START;	mostek_write(regs + MOSTEK_HOUR, tmp);	MSTK_SET_REG_SEC(regs,0);	MSTK_SET_REG_MIN(regs,0);	MSTK_SET_REG_HOUR(regs,0);	MSTK_SET_REG_DOW(regs,5);	MSTK_SET_REG_DOM(regs,1);	MSTK_SET_REG_MONTH(regs,8);	MSTK_SET_REG_YEAR(regs,1996 - MSTK_YEAR_ZERO);	tmp = mostek_read(regs + MOSTEK_CREG);	tmp &= ~MSTK_CREG_WRITE;	mostek_write(regs + MOSTEK_CREG, tmp);	spin_unlock_irq(&mostek_lock);	/* Ensure the kick start bit is off. If it isn't, turn it off. */	while (mostek_read(regs + MOSTEK_HOUR) & MSTK_KICK_START) {		prom_printf("CLOCK: Kick start still on!\n");		spin_lock_irq(&mostek_lock);		tmp = mostek_read(regs + MOSTEK_CREG);		tmp |= MSTK_CREG_WRITE;		mostek_write(regs + MOSTEK_CREG, tmp);		tmp = mostek_read(regs + MOSTEK_HOUR);		tmp &= ~MSTK_KICK_START;		mostek_write(regs + MOSTEK_HOUR, tmp);		tmp = mostek_read(regs + MOSTEK_CREG);		tmp &= ~MSTK_CREG_WRITE;		mostek_write(regs + MOSTEK_CREG, tmp);		spin_unlock_irq(&mostek_lock);	}	prom_printf("CLOCK: Kick start procedure successful.\n");}/* Return nonzero if the clock chip battery is low. */static int __init has_low_battery(void){	unsigned long regs = mstk48t02_regs;	u8 data1, data2;	spin_lock_irq(&mostek_lock);	data1 = mostek_read(regs + MOSTEK_EEPROM);	/* Read some data. */	mostek_write(regs + MOSTEK_EEPROM, ~data1);	/* Write back the complement. */	data2 = mostek_read(regs + MOSTEK_EEPROM);	/* Read back the complement. */	mostek_write(regs + MOSTEK_EEPROM, data1);	/* Restore original value. */	spin_unlock_irq(&mostek_lock);	return (data1 == data2);	/* Was the write blocked? */}#ifndef BCD_TO_BIN#define BCD_TO_BIN(val) (((val)&15) + ((val)>>4)*10)#endif#ifndef BIN_TO_BCD#define BIN_TO_BCD(val) ((((val)/10)<<4) + (val)%10)#endif/* Probe for the real time clock chip. */static void __init set_system_time(void){	unsigned int year, mon, day, hour, min, sec;	unsigned long mregs = mstk48t02_regs;#ifdef CONFIG_PCI	unsigned long dregs = ds1287_regs;#else	unsigned long dregs = 0UL;#endif	u8 tmp;	if (!mregs && !dregs) {		prom_printf("Something wrong, clock regs not mapped yet.\n");		prom_halt();	}			if (mregs) {		spin_lock_irq(&mostek_lock);		/* Traditional Mostek chip. */		tmp = mostek_read(mregs + MOSTEK_CREG);		tmp |= MSTK_CREG_READ;		mostek_write(mregs + MOSTEK_CREG, tmp);		sec = MSTK_REG_SEC(mregs);		min = MSTK_REG_MIN(mregs);		hour = MSTK_REG_HOUR(mregs);		day = MSTK_REG_DOM(mregs);		mon = MSTK_REG_MONTH(mregs);		year = MSTK_CVT_YEAR( MSTK_REG_YEAR(mregs) );	} else {		int i;		/* Dallas 12887 RTC chip. */		/* Stolen from arch/i386/kernel/time.c, see there for		 * credits and descriptive comments.		 */		for (i = 0; i < 1000000; i++) {			if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)				break;			udelay(10);		}		for (i = 0; i < 1000000; i++) {			if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))				break;			udelay(10);		}		do {			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);		}		if ((year += 1900) < 1970)			year += 100;	}	xtime.tv_sec = mktime(year, mon, day, hour, min, sec);	xtime.tv_usec = 0;

⌨️ 快捷键说明

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