plan 9 kernel history: overview | file list | diff list

2002/0410/pc/i8253.c (diff list | history)

2002/0409/sys/src/9/pc/i8253.c:46,562002/0410/sys/src/9/pc/i8253.c:46,51 (short | long | prev | next)
2000/0623    
	Trigger=0x0,		/* interrupt on terminal count */ 
	Sstrobe=0x8,		/* software triggered strobe */ 
1997/0327    
 
2000/0623    
	/* counter 2 controls */ 
	C2gate=	0x1, 
	C2speak=0x2, 
	C2out=	0x10, 
                 
2002/0409    
	/* T2ctl bits */ 
	T2gate=	(1<<0),		/* enable T2 counting */ 
	T2spkr=	(1<<1),		/* connect T2 out to speaker */ 
2002/0409/sys/src/9/pc/i8253.c:57,832002/0410/sys/src/9/pc/i8253.c:52,74
2002/0409    
	T2out=	(1<<5),		/* output of T2 */ 
 
1997/0327    
	Freq=	1193182,	/* Real clock frequency */ 
2002/0409    
	Tickshift= 8,		/* increase tick wriggle room */ 
2000/0623    
                 
2000/0706    
	Minusec=20,		/* minimum cycles for a clock interrupt */ 
                 
2000/0623    
	FreqMul=16,		/* extra accuracy in fastticks/Freq calculation; ok up to ~8ghz */ 
2002/0410    
	Tickshift=8,		/* extra accuracy */ 
	MaxPeriod=Freq/HZ, 
	MinPeriod=Freq/(100*HZ), 
1997/0327    
}; 
 
2000/0623    
static struct 
{ 
2000/0627    
	Lock; 
2002/0410    
	ulong	period;		/* current clock period */ 
2000/0701    
	int	enabled; 
2000/0627    
	int	mode; 
2000/0623    
	vlong	when;		/* next fastticks a clock interrupt should occur */ 
2002/0405    
	vlong	timerwhen;	/* next fastticks a cycintr happens; 0 == infinity */ 
2000/0623    
	long	fastperiod;	/* fastticks/hz */ 
	long	fast2freq;	/* fastticks*FreqMul/Freq */ 
2002/0410    
	uvlong	hz; 
2002/0405    
 
2002/0409    
	ushort	last;		/* last value of clock 1 */ 
	uvlong	ticks;		/* cumulative ticks of counter 1 */ 
2000/0623    
}i8253; 
2000/0622    
 
2002/0410    
 
1997/0327    
void 
2002/0405    
i8253init(void) 
1997/0327    
{ 
2002/0409/sys/src/9/pc/i8253.c:87,982002/0410/sys/src/9/pc/i8253.c:78,89
2002/0405    
	ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl"); 
2000/0623    
 
2002/0405    
	/* 
	 *  set interrupting clock for 1/HZ seconds 
2002/0410    
	 *  enable a 1/HZ interrupt for providing scheduling interrupts 
2002/0405    
	 */ 
	outb(Tmode, Load0|Square); 
	i8253.mode = Square; 
	outb(T0cntr, (Freq/HZ));	/* low byte */ 
	outb(T0cntr, (Freq/HZ)>>8);	/* high byte */ 
2002/0410    
	i8253.period = Freq/HZ; 
1998/0903    
 
2002/0405    
	/* 
2002/0409    
	 *  enable a longer period counter to use as a clock 
2002/0409/sys/src/9/pc/i8253.c:100,1092002/0410/sys/src/9/pc/i8253.c:91,101
2002/0409    
	outb(Tmode, Load2|Square); 
	outb(T2cntr, 0);		/* low byte */ 
	outb(T2cntr, 0);		/* high byte */ 
2002/0410    
	i8253.period = Freq/HZ; 
2002/0409    
	x = inb(T2ctl); 
	x |= T2gate; 
	outb(T2ctl, x); 
2002/0405    
                 
2002/0410    
	 
2002/0405    
	/* 
	 * Introduce a little delay to make sure the count is 
	 * latched and the timer is counting down; with a fast 
2002/0409/sys/src/9/pc/i8253.c:189,2852002/0410/sys/src/9/pc/i8253.c:181,238
1999/0131    
		m->cpumhz = (cpufreq + cpufreq/200)/1000000; 
		m->cpuhz = cpufreq; 
	} 
2002/0410    
 
	i8253.hz = Freq<<Tickshift; 
1997/0327    
} 
 
2000/0627    
/* 
 * schedule the next interrupt 
2002/0405    
 * timerwhen is the time of the next interrupt 
2000/0627    
 */ 
2000/0621    
static void 
2000/0627    
clockintrsched0(vlong next) 
2002/0410    
ulong i8253periodset; 
 
void 
i8253timerset(uvlong next) 
2000/0621    
{ 
2000/0623    
	vlong now; 
	long set; 
2002/0410    
	ulong period; 
	ulong want; 
	ulong now; 
2000/0623    
 
2002/0405    
	i8253.timerwhen = next; 
2000/0627    
	if(i8253.mode == Square && next == 0) 
		return; 
2002/0410    
	want = next>>Tickshift; 
	now = i8253.ticks;	/* assuming whomever called us just did fastticks() */ 
2000/0627    
 
2000/0623    
	now = fastticks(nil); 
2000/0627    
	if(next || now < i8253.when - i8253.fastperiod || now > i8253.when - ((3*i8253.fastperiod)>>2)){ 
		if(next > i8253.when) 
			next = i8253.when; 
		set = (long)(next - now) * FreqMul / i8253.fast2freq; 
		set -= 3;	/* three cycles for the count to take effect: outb, outb, wait */ 
		if(i8253.mode != Trigger){ 
			outb(Tmode, Load0|Trigger); 
			i8253.mode = Trigger; 
			set--; 
		} 
2000/0706    
		if(set < Minusec) 
			set = Minusec; 
2000/0627    
		outb(T0cntr, set);	/* low byte */ 
		outb(T0cntr, set>>8);	/* high byte */ 
	}else if(i8253.mode != Square){ 
		i8253.mode = Square; 
		outb(Tmode, Load0|Square); 
		outb(T0cntr, (Freq/HZ));	/* low byte */ 
		outb(T0cntr, (Freq/HZ)>>8);	/* high byte */ 
2002/0410    
	period = MaxPeriod; 
	if(next != 0){ 
		period = want - now; 
		if(period < MinPeriod) 
			period = MinPeriod; 
		else if(period > (4*MaxPeriod)/5)	/* strong attraction to MaxPeriod */ 
			period = MaxPeriod; 
2000/0627    
	} 
} 
2000/0623    
 
2000/0701    
int 
2002/0405    
havetimer(void) 
2000/0701    
{ 
2002/0405    
	return i8253.enabled; 
2000/0701    
} 
2002/0410    
	/* histeresis */ 
	if(i8253.period != period){ 
		ilock(&i8253); 
		/* load new value */ 
		outb(Tmode, Load0|Square); 
		outb(T0cntr, period);		/* low byte */ 
		outb(T0cntr, period>>8);	/* high byte */ 
2000/0701    
 
2000/0627    
void 
clockintrsched(void) 
{ 
	vlong next; 
                 
	ilock(&i8253); 
2002/0405    
	if(i8253.enabled){ 
		next = timernext(); 
		if(next != i8253.timerwhen) 
2000/0701    
			clockintrsched0(next); 
2002/0410    
		/* remember period */ 
		i8253.period = period; 
		i8253periodset++; 
		iunlock(&i8253); 
2000/0701    
	} 
2000/0627    
	iunlock(&i8253); 
} 
 
static void 
clockintr0(Ureg* ureg, void *v) 
2002/0410    
i8253clock(Ureg* ureg, void*) 
2000/0627    
{ 
	vlong now, when; 
2000/0713    
                 
2002/0405    
	/* goes with syncing in squidboy */ 
	if(m->havetsc) 
		rdtsc(&m->lasttsc); 
2000/0627    
                 
	now = fastticks(nil); 
	when = i8253.when; 
2002/0406    
                 
2000/0627    
	if(now >= i8253.when){ 
		clockintr(ureg, v); 
		do 
			i8253.when += i8253.fastperiod; 
		while(i8253.when < now); 
	} 
2002/0405    
	if(i8253.timerwhen || i8253.mode != Square) 
		clockintrsched0(checktimer(ureg, v)); 
2002/0410    
	timerintr(ureg, 0); 
2000/0621    
} 
 
1997/0327    
void 
i8253enable(void) 
{ 
2002/0405    
	uvlong hz; 
                 
	i8253.when = fastticks(&hz); 
	i8253.fastperiod = (hz + HZ/2) / HZ; 
	i8253.fast2freq = (hz * FreqMul) / Freq; 
2000/0701    
	i8253.enabled = 1; 
2000/0621    
	intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock"); 
2002/0410    
	i8253.period = Freq/HZ; 
	intrenable(IrqCLOCK, i8253clock, 0, BUSUNKNOWN, "clock"); 
1997/0327    
} 
1998/0710    
 
/* 
2002/0409/sys/src/9/pc/i8253.c:294,3002002/0410/sys/src/9/pc/i8253.c:247,253
2002/0405    
	uvlong ticks; 
 
1998/0710    
	if(hz) 
2002/0409    
		*hz = Freq<<Tickshift; 
2002/0410    
		*hz = i8253.hz; 
2002/0405    
 
2002/0409    
	ilock(&i8253); 
	outb(Tmode, Latch2); 
2002/0409/sys/src/9/pc/i8253.c:304,3102002/0410/sys/src/9/pc/i8253.c:257,263
2002/0409    
	if(y < i8253.last) 
		x = i8253.last - y; 
2002/0405    
	else 
2002/0409    
		x = i8253.last + (0x1000 - y); 
2002/0410    
		x = i8253.last + (0x10000 - y); 
2002/0409    
	i8253.last = y; 
	i8253.ticks += x>>1; 
	ticks = i8253.ticks; 
2002/0409/sys/src/9/pc/i8253.c:313,3232002/0410/sys/src/9/pc/i8253.c:266,299
2002/0409    
	return ticks<<Tickshift; 
2002/0405    
} 
 
/* 
 *  return value and speed of timer set in arch->clockenable 
 */ 
vlong 
fastticks(uvlong *hz) 
2002/0410    
void 
delay(int millisecs) 
2002/0405    
{ 
	return (*arch->fastclock)(hz); 
2002/0410    
	millisecs *= m->loopconst; 
	if(millisecs <= 0) 
		millisecs = 1; 
	aamloop(millisecs); 
} 
 
void 
microdelay(int microsecs) 
{ 
	microsecs *= m->loopconst; 
	microsecs /= 1000; 
	if(microsecs <= 0) 
		microsecs = 1; 
	aamloop(microsecs); 
} 
 
ulong 
TK2MS(ulong ticks) 
{ 
	uvlong t, hz; 
 
	t = ticks; 
	hz = HZ; 
	t *= 1000L; 
	t = t/hz; 
	ticks = t; 
	return ticks; 
1998/0710    
} 


source code copyright © 1990-2005 Lucent Technologies; see license
Plan 9 distribution
comments to russ cox (rsc@swtch.com)