time.c

来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 1,282 行 · 第 1/3 页

C
1,282
字号
/* $Id: time.c,v 1.42 2002/01/23 14:33:55 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/module.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/time.h>#include <linux/timex.h>#include <linux/init.h>#include <linux/ioport.h>#include <linux/mc146818rtc.h>#include <linux/delay.h>#include <linux/profile.h>#include <linux/bcd.h>#include <linux/jiffies.h>#include <linux/cpufreq.h>#include <linux/percpu.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>#include <asm/smp.h>#include <asm/sections.h>#include <asm/cpudata.h>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;#endifextern unsigned long wall_jiffies;u64 jiffies_64 = INITIAL_JIFFIES;EXPORT_SYMBOL(jiffies_64);static unsigned long mstk48t08_regs = 0UL;static unsigned long mstk48t59_regs = 0UL;static int set_rtc_mmss(unsigned long);struct sparc64_tick_ops *tick_ops;#define TICK_PRIV_BIT	(1UL << 63)static void tick_disable_protection(void){	/* Set things up so user can access tick register for profiling	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy	 * read back of %tick after writing it.	 */	__asm__ __volatile__(	"	ba,pt	%%xcc, 1f\n"	"	 nop\n"	"	.align	64\n"	"1:	rd	%%tick, %%g2\n"	"	add	%%g2, 6, %%g2\n"	"	andn	%%g2, %0, %%g2\n"	"	wrpr	%%g2, 0, %%tick\n"	"	rdpr	%%tick, %%g0"	: /* no outputs */	: "r" (TICK_PRIV_BIT)	: "g2");}static void tick_init_tick(unsigned long offset){	tick_disable_protection();	__asm__ __volatile__(	"	rd	%%tick, %%g1\n"	"	andn	%%g1, %1, %%g1\n"	"	ba,pt	%%xcc, 1f\n"	"	 add	%%g1, %0, %%g1\n"	"	.align	64\n"	"1:	wr	%%g1, 0x0, %%tick_cmpr\n"	"	rd	%%tick_cmpr, %%g0"	: /* no outputs */	: "r" (offset), "r" (TICK_PRIV_BIT)	: "g1");}static unsigned long tick_get_tick(void){	unsigned long ret;	__asm__ __volatile__("rd	%%tick, %0\n\t"			     "mov	%0, %0"			     : "=r" (ret));	return ret & ~TICK_PRIV_BIT;}static unsigned long tick_get_compare(void){	unsigned long ret;	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"			     "mov	%0, %0"			     : "=r" (ret));	return ret;}static unsigned long tick_add_compare(unsigned long adj){	unsigned long new_compare;	/* 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	 */	__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"			     "ba,pt	%%xcc, 1f\n\t"			     " add	%0, %1, %0\n\t"			     ".align	64\n"			     "1:\n\t"			     "wr	%0, 0, %%tick_cmpr\n\t"			     "rd	%%tick_cmpr, %%g0"			     : "=&r" (new_compare)			     : "r" (adj));	return new_compare;}static unsigned long tick_add_tick(unsigned long adj, unsigned long offset){	unsigned long new_tick, tmp;	/* Also need to handle Blackbird bug here too. */	__asm__ __volatile__("rd	%%tick, %0\n\t"			     "add	%0, %2, %0\n\t"			     "wrpr	%0, 0, %%tick\n\t"			     "andn	%0, %4, %1\n\t"			     "ba,pt	%%xcc, 1f\n\t"			     " add	%1, %3, %1\n\t"			     ".align	64\n"			     "1:\n\t"			     "wr	%1, 0, %%tick_cmpr\n\t"			     "rd	%%tick_cmpr, %%g0"			     : "=&r" (new_tick), "=&r" (tmp)			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));	return new_tick;}static struct sparc64_tick_ops tick_operations = {	.init_tick	=	tick_init_tick,	.get_tick	=	tick_get_tick,	.get_compare	=	tick_get_compare,	.add_tick	=	tick_add_tick,	.add_compare	=	tick_add_compare,	.softint_mask	=	1UL << 0,};static void stick_init_tick(unsigned long offset){	tick_disable_protection();	/* Let the user get at STICK too. */	__asm__ __volatile__(	"	rd	%%asr24, %%g2\n"	"	andn	%%g2, %0, %%g2\n"	"	wr	%%g2, 0, %%asr24"	: /* no outputs */	: "r" (TICK_PRIV_BIT)	: "g1", "g2");	__asm__ __volatile__(	"	rd	%%asr24, %%g1\n"	"	andn	%%g1, %1, %%g1\n"	"	add	%%g1, %0, %%g1\n"	"	wr	%%g1, 0x0, %%asr25"	: /* no outputs */	: "r" (offset), "r" (TICK_PRIV_BIT)	: "g1");}static unsigned long stick_get_tick(void){	unsigned long ret;	__asm__ __volatile__("rd	%%asr24, %0"			     : "=r" (ret));	return ret & ~TICK_PRIV_BIT;}static unsigned long stick_get_compare(void){	unsigned long ret;	__asm__ __volatile__("rd	%%asr25, %0"			     : "=r" (ret));	return ret;}static unsigned long stick_add_tick(unsigned long adj, unsigned long offset){	unsigned long new_tick, tmp;	__asm__ __volatile__("rd	%%asr24, %0\n\t"			     "add	%0, %2, %0\n\t"			     "wr	%0, 0, %%asr24\n\t"			     "andn	%0, %4, %1\n\t"			     "add	%1, %3, %1\n\t"			     "wr	%1, 0, %%asr25"			     : "=&r" (new_tick), "=&r" (tmp)			     : "r" (adj), "r" (offset), "r" (TICK_PRIV_BIT));	return new_tick;}static unsigned long stick_add_compare(unsigned long adj){	unsigned long new_compare;	__asm__ __volatile__("rd	%%asr25, %0\n\t"			     "add	%0, %1, %0\n\t"			     "wr	%0, 0, %%asr25"			     : "=&r" (new_compare)			     : "r" (adj));	return new_compare;}static struct sparc64_tick_ops stick_operations = {	.init_tick	=	stick_init_tick,	.get_tick	=	stick_get_tick,	.get_compare	=	stick_get_compare,	.add_tick	=	stick_add_tick,	.add_compare	=	stick_add_compare,	.softint_mask	=	1UL << 16,};/* On Hummingbird the STICK/STICK_CMPR register is implemented * in I/O space.  There are two 64-bit registers each, the * first holds the low 32-bits of the value and the second holds * the high 32-bits. * * Since STICK is constantly updating, we have to access it carefully. * * The sequence we use to read is: * 1) read low * 2) read high * 3) read low again, if it rolled over increment high by 1 * * Writing STICK safely is also tricky: * 1) write low to zero * 2) write high * 3) write low */#define HBIRD_STICKCMP_ADDR	0x1fe0000f060UL#define HBIRD_STICK_ADDR	0x1fe0000f070ULstatic unsigned long __hbird_read_stick(void){	unsigned long ret, tmp1, tmp2, tmp3;	unsigned long addr = HBIRD_STICK_ADDR;	__asm__ __volatile__("ldxa	[%1] %5, %2\n\t"			     "add	%1, 0x8, %1\n\t"			     "ldxa	[%1] %5, %3\n\t"			     "sub	%1, 0x8, %1\n\t"			     "ldxa	[%1] %5, %4\n\t"			     "cmp	%4, %2\n\t"			     "blu,a,pn	%%xcc, 1f\n\t"			     " add	%3, 1, %3\n"			     "1:\n\t"			     "sllx	%3, 32, %3\n\t"			     "or	%3, %4, %0\n\t"			     : "=&r" (ret), "=&r" (addr),			       "=&r" (tmp1), "=&r" (tmp2), "=&r" (tmp3)			     : "i" (ASI_PHYS_BYPASS_EC_E), "1" (addr));	return ret;}static unsigned long __hbird_read_compare(void){	unsigned long low, high;	unsigned long addr = HBIRD_STICKCMP_ADDR;	__asm__ __volatile__("ldxa	[%2] %3, %0\n\t"			     "add	%2, 0x8, %2\n\t"			     "ldxa	[%2] %3, %1"			     : "=&r" (low), "=&r" (high), "=&r" (addr)			     : "i" (ASI_PHYS_BYPASS_EC_E), "2" (addr));	return (high << 32UL) | low;}static void __hbird_write_stick(unsigned long val){	unsigned long low = (val & 0xffffffffUL);	unsigned long high = (val >> 32UL);	unsigned long addr = HBIRD_STICK_ADDR;	__asm__ __volatile__("stxa	%%g0, [%0] %4\n\t"			     "add	%0, 0x8, %0\n\t"			     "stxa	%3, [%0] %4\n\t"			     "sub	%0, 0x8, %0\n\t"			     "stxa	%2, [%0] %4"			     : "=&r" (addr)			     : "0" (addr), "r" (low), "r" (high),			       "i" (ASI_PHYS_BYPASS_EC_E));}static void __hbird_write_compare(unsigned long val){	unsigned long low = (val & 0xffffffffUL);	unsigned long high = (val >> 32UL);	unsigned long addr = HBIRD_STICKCMP_ADDR + 0x8UL;	__asm__ __volatile__("stxa	%3, [%0] %4\n\t"			     "sub	%0, 0x8, %0\n\t"			     "stxa	%2, [%0] %4"			     : "=&r" (addr)			     : "0" (addr), "r" (low), "r" (high),			       "i" (ASI_PHYS_BYPASS_EC_E));}static void hbtick_init_tick(unsigned long offset){	unsigned long val;	tick_disable_protection();	/* XXX This seems to be necessary to 'jumpstart' Hummingbird	 * XXX into actually sending STICK interrupts.  I think because	 * XXX of how we store %tick_cmpr in head.S this somehow resets the	 * XXX {TICK + STICK} interrupt mux.  -DaveM	 */	__hbird_write_stick(__hbird_read_stick());	val = __hbird_read_stick() & ~TICK_PRIV_BIT;	__hbird_write_compare(val + offset);}static unsigned long hbtick_get_tick(void){	return __hbird_read_stick() & ~TICK_PRIV_BIT;}static unsigned long hbtick_get_compare(void){	return __hbird_read_compare();}static unsigned long hbtick_add_tick(unsigned long adj, unsigned long offset){	unsigned long val;	val = __hbird_read_stick() + adj;	__hbird_write_stick(val);	val &= ~TICK_PRIV_BIT;	__hbird_write_compare(val + offset);	return val;}static unsigned long hbtick_add_compare(unsigned long adj){	unsigned long val = __hbird_read_compare() + adj;	val &= ~TICK_PRIV_BIT;	__hbird_write_compare(val);	return val;}static struct sparc64_tick_ops hbtick_operations = {	.init_tick	=	hbtick_init_tick,	.get_tick	=	hbtick_get_tick,	.get_compare	=	hbtick_get_compare,	.add_tick	=	hbtick_add_tick,	.add_compare	=	hbtick_add_compare,	.softint_mask	=	1UL << 0,};/* 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;static unsigned long timer_ticks_per_usec_quotient;static unsigned long timer_ticks_per_nsec_quotient;#define TICK_SIZE (tick_nsec / 1000)static inline void timer_check_rtc(void){	/* last time the cmos clock got updated */

⌨️ 快捷键说明

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