Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/pc/i8253.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname pc/i8253.c 1997/0327
## diff -e /dev/null /n/emeliedump/1997/0327/sys/src/brazil/pc/i8253.c
0a
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

/*
 *  8253 timer
 */
enum
{
	T0cntr=	0x40,		/* counter ports */
	T1cntr=	0x41,		/* ... */
	T2cntr=	0x42,		/* ... */
	Tmode=	0x43,		/* mode port */

	/* commands */
	Latch0=	0x00,		/* latch counter 0's value */
	Load0=	0x30,		/* load counter 0 with 2 bytes */

	/* modes */
	Square=	0x36,		/* periodic square wave */
	Trigger= 0x30,		/* interrupt on terminal count */

	Freq=	1193182,	/* Real clock frequency */
};

void
i8253init(int aalcycles)
{
	int cpufreq, loops, incr, x, y;
	static int initialised;

	if(initialised == 0){
		initialised = 1;
		/*
		 *  set clock for 1/HZ seconds
		 */
		outb(Tmode, Load0|Square);
		outb(T0cntr, (Freq/HZ));	/* low byte */
		outb(T0cntr, (Freq/HZ)>>8);	/* high byte */
	}

	/* find biggest loop that doesn't wrap */
	incr = 16000000/(aalcycles*HZ*2);
	x = 2000;
	for(loops = incr; loops < 64*1024; loops += incr) {
	
		/*
		 *  measure time for the loop
		 *
		 *			MOVL	loops,CX
		 *	aaml1:	 	AAM
		 *			LOOP	aaml1
		 *
		 *  the time for the loop should be independent of external
		 *  cache and memory system since it fits in the execution
		 *  prefetch buffer.
		 *
		 */
		outb(Tmode, Latch0);
		x = inb(T0cntr);
		x |= inb(T0cntr)<<8;
		aamloop(loops);
		outb(Tmode, Latch0);
		y = inb(T0cntr);
		y |= inb(T0cntr)<<8;
		x -= y;
	
		if(x < 0)
			x += Freq/HZ;

		if(x > Freq/(3*HZ))
			break;
	}

	/*
	 *  counter  goes at twice the frequency, once per transition,
	 *  i.e., twice per square wave
	 */
	x >>= 1;

	/*
 	 *  figure out clock frequency and a loop multiplier for delay().
	 */
	cpufreq = loops*((aalcycles*Freq)/x);
	m->loopconst = (cpufreq/1000)/aalcycles;	/* AAM+LOOP's for 1 ms */

	/*
	 *  add in possible 0.5% error and convert to MHz
	 */
	m->cpumhz = (cpufreq + cpufreq/200)/1000000;
}

void
i8253enable(void)
{
	intrenable(VectorCLOCK, clockintr, 0, BUSUNKNOWN);
}
.
## diffname pc/i8253.c 1998/0710
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/pc/i8253.c /n/emeliedump/1998/0710/sys/src/brazil/pc/i8253.c
100a

Lock i8253lock;

/*
 *  return time elapsed since clock start in
 *  10ths of nanoseconds
 */
uvlong
i8253read(uvlong *hz)
{
	if(hz)
		*hz = HZ;
	return m->ticks;
}
.
## diffname pc/i8253.c 1998/0819
## diff -e /n/emeliedump/1998/0710/sys/src/brazil/pc/i8253.c /n/emeliedump/1998/0819/sys/src/brazil/pc/i8253.c
102,103d
## diffname pc/i8253.c 1998/0903
## diff -e /n/emeliedump/1998/0819/sys/src/brazil/pc/i8253.c /n/emeliedump/1998/0903/sys/src/brazil/pc/i8253.c
42a

		/*
		 * Introduce a little delay to make sure the count is
		 * latched and the timer is counting down; with a fast
		 * enough processor this may not be the case.
		 * The i8254 (which this probably is) has a read-back
		 * command which can be used to make sure the counting
		 * register has been written into the counting element.
		 */
		x = (Freq/HZ);
		for(loops = 0; loops < 100000 && x >= (Freq/HZ); loops++){
			outb(Tmode, Latch0);
			x = inb(T0cntr);
			x |= inb(T0cntr)<<8;
		}
.
## diffname pc/i8253.c 1998/0910
## diff -e /n/emeliedump/1998/0903/sys/src/brazil/pc/i8253.c /n/emeliedump/1998/0910/sys/src/brazil/pc/i8253.c
114c
	intrenable(IrqCLOCK, clockintr, 0, BUSUNKNOWN);
.
## diffname pc/i8253.c 1999/0131
## diff -e /n/emeliedump/1998/0910/sys/src/brazil/pc/i8253.c /n/emeliedump/1999/0131/sys/src/brazil/pc/i8253.c
105,108c
	if(havecycleclock){

		/* counter goes up by 2*Freq */
		b = (b-a)<<1;
		b *= Freq;
		b /= x;

		/*
		 *  round to the nearest megahz
		 */
		m->cpumhz = (b+500000)/1000000L;
		m->cpuhz = b;
	} else {
		/*
		 *  add in possible 0.5% error and convert to MHz
		 */
		m->cpumhz = (cpufreq + cpufreq/200)/1000000;
		m->cpuhz = cpufreq;
	}
.
102c
	cpufreq = loops*((aalcycles*2*Freq)/x);
.
100a
	 *  n.b. counter goes up by 2*Freq
.
94,99d
81a
		if(havecycleclock)
			rdmsr(0x10, &b);
.
77a
		if(havecycleclock)
			rdmsr(0x10, &a);
.
32a
	vlong a, b;
.
30c
i8253init(int aalcycles, int havecycleclock)
.
## diffname pc/i8253.c 1999/0228
## diff -e /n/emeliedump/1999/0131/sys/src/brazil/pc/i8253.c /n/emeliedump/1999/0228/sys/src/brazil/pc/i8253.c
140,141c
		*hz = HZ*100;
	return m->ticks*100;
.
134c
 *  100 times hz
.
## diffname pc/i8253.c 1999/0714
## diff -e /n/emeliedump/1999/0228/sys/src/brazil/pc/i8253.c /n/emeliedump/1999/0714/sys/src/brazil/pc/i8253.c
37a
		ioalloc(T0cntr, 4, 0, "i8253");
.
## diffname pc/i8253.c 1999/0819
## diff -e /n/emeliedump/1999/0714/sys/src/brazil/pc/i8253.c /n/emeliedump/1999/0819/sys/src/brazil/pc/i8253.c
130c
	intrenable(IrqCLOCK, clockintr, 0, BUSUNKNOWN, "clock");
.
## diffname pc/i8253.c 2000/0621
## diff -e /n/emeliedump/1999/0819/sys/src/brazil/pc/i8253.c /n/emeliedump/2000/0621/sys/src/9/pc/i8253.c
130c
	intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock");
.
126a
static void
clockintr0(Ureg* ureg, void *v)
{
	loopbackintr();
	clockintr(ureg, v);
}

.
## diffname pc/i8253.c 2000/0622
## diff -e /n/emeliedump/2000/0621/sys/src/9/pc/i8253.c /n/emeliedump/2000/0622/sys/src/9/pc/i8253.c
130c
	loopbackintr(ureg);
.
126a
int
i8253readcnt(void)
{
	ilock(&i8253lock);
	iunlock(&i8253lock);
}

.
28a
static Lock	i8253lock;

.
23,24c
	Square=	0x6,		/* periodic square wave */
	Trigger= 0x0,		/* interrupt on terminal count */
.
19a
	Load0l=	0x10,		/* load counter 0's lsb */
	Load0m=	0x20,		/* load counter 0's msb */
.
16c
	Tmode=	0x43,		/* mode port (control word register) */
.
## diffname pc/i8253.c 2000/0623
## diff -e /n/emeliedump/2000/0622/sys/src/9/pc/i8253.c /n/emeliedump/2000/0623/sys/src/9/pc/i8253.c
147a
	i8253.when = fastticks(nil);
	i8253.fastperiod = (m->cpuhz + HZ/2) / HZ;
	i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq;
.
141c
	vlong now;
	long set;

	now = fastticks(nil);
	while(i8253.when < now)
		i8253.when += i8253.fastperiod;
	set = (long)(i8253.when - now) * FreqMul / i8253.fast2freq;
	set -= 3;	/* three cycles for the count to take effect: outb, outb, wait */
lastfast = now;
	outb(T0cntr, set);	/* low byte */
	outb(T0cntr, set>>8);	/* high byte */

	checkcycintr(ureg, v);
.
134,135c
	int v;

	ilock(&i8253.lock);
	if(cntr == 2){
		outb(Tmode, Rdback|Rd2cntr);
		v = inb(T2cntr) << 16;
		v |= inb(T2cntr);
		v |= inb(T2cntr) << 8;
	}else if(cntr == 0){
		outb(Tmode, Rdback|Rd0cntr);
		v = inb(T0cntr) << 16;
		v |= inb(T0cntr);
		v |= inb(T0cntr) << 8;
	}else if(cntr == 3){
		vlong nf = fastticks(nil);
		long set;

		set = (long)(nf - lastfast) * 100 / (long)((vlong)m->cpuhz * 100 / Freq);
		set = (Freq/HZ) - set;
		set -= 3 - 1;	/* outb, outb, wait - outb(mode) */
		outb(Tmode, Rdback|Rdnstat|Rd0cntr);
		v = inb(T0cntr);
		v |= inb(T0cntr) << 8;
		v = set - v;
	}else if(cntr == 4){
		vlong nf = fastticks(nil);
		long set;

		set = (long)(nf - lastfast) * 16 / (long)((vlong)m->cpuhz * 16 / Freq);
		set = (Freq/HZ) - set;
		set -= 3 - 1;	/* outb, outb, wait - outb(mode) */
		outb(Tmode, Rdback|Rdnstat|Rd0cntr);
		v = inb(T0cntr);
		v |= inb(T0cntr) << 8;
		v = set - v;
	}else{
		vlong nf = fastticks(nil);
		long set;

		set = (nf - lastfast) * Freq / m->cpuhz;
		set = (Freq/HZ) - set;
		set -= 3 - 1;	/* outb, outb, wait - outb(mode) */
		outb(Tmode, Rdback|Rdnstat|Rd0cntr);
		v = inb(T0cntr);
		v |= inb(T0cntr) << 8;
		v = set - v;
	}
	iunlock(&i8253.lock);
	return v;
.
132c
i8253readcnt(int cntr)
.
130a
static vlong lastfast;

.
128a

outb(Tmode, Load0|Trigger);
outb(T0cntr, (Freq/HZ));	/* low byte */
outb(T0cntr, (Freq/HZ)>>8);	/* high byte */
.
42a
		ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");

.
31c
static struct
{
	Lock	lock;
	vlong	when;		/* next fastticks a clock interrupt should occur */
	long	fastperiod;	/* fastticks/hz */
	long	fast2freq;	/* fastticks*FreqMul/Freq */
}i8253;
.
28a

	FreqMul=16,		/* extra accuracy in fastticks/Freq calculation; ok up to ~8ghz */
.
27a
	/* counter 2 controls */
	C2gate=	0x1,
	C2speak=0x2,
	C2out=	0x10,

.
26c
	Trigger=0x0,		/* interrupt on terminal count */
	Sstrobe=0x8,		/* software triggered strobe */
.
24a
	ModeMsk=0xe,
.
23a
	/* 8254 read-back command: everything > pc-at has an 8254 */
	Rdback=	0xc0,		/* readback counters & status */
	Rdnstat=0x10,		/* don't read status */
	Rdncnt=	0x20,		/* don't read counter value */
	Rd0cntr=0x02,		/* read back for which counter */
	Rd1cntr=0x04,
	Rd2cntr=0x08,

.
22a
	Latch2=	0x80,		/* latch counter 2's value */
	Load2l=	0x90,		/* load counter 2's lsb */
	Load2m=	0xa0,		/* load counter 2's msb */
	Load2=	0xb0,		/* load counter 2 with 2 bytes */
.
16a
	T2ctl=	0x61,		/* counter 2 control port */
.
## diffname pc/i8253.c 2000/0624
## diff -e /n/emeliedump/2000/0623/sys/src/9/pc/i8253.c /n/emeliedump/2000/0624/sys/src/9/pc/i8253.c
234a
#endif
.
232d
223a
#ifdef SETNEXT
.
167,220d
165c
#ifdef SETNEXT
set up clock so it is reloaded every interrupt
	outb(Tmode, Load0|Trigger);
	outb(T0cntr, (Freq/HZ));	/* low byte */
	outb(T0cntr, (Freq/HZ)>>8);	/* high byte */
#endif
.
159,162d
## diffname pc/i8253.c 2000/0627
## diff -e /n/emeliedump/2000/0624/sys/src/9/pc/i8253.c /n/emeliedump/2000/0627/sys/src/9/pc/i8253.c
184,185c
void
clockintrsched(void)
{
	vlong next;

	ilock(&i8253);
	next = cycintrnext();
	if(next != i8253.cycwhen)
		clockintrsched0(next);
	iunlock(&i8253);
}

static void
clockintr0(Ureg* ureg, void *v)
{
	vlong now, when;

	now = fastticks(nil);
	when = i8253.when;
	if(now >= i8253.when){
		clockintr(ureg, v);
		do
			i8253.when += i8253.fastperiod;
		while(i8253.when < now);
	}
	if(i8253.cycwhen || i8253.mode != Square)
		clockintrsched0(checkcycintr(ureg, v));
.
176,182c
	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--;
		}
		if(set < 3)
			set = 5;
		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 */
	}
}
.
174a
	i8253.cycwhen = next;
	if(i8253.mode == Square && next == 0)
		return;

.
171d
169c
clockintrsched0(vlong next)
.
161,167c
/*
 * schedule the next interrupt
 * cycwhen is the next time for the cycle counter routines
 */
.
76a
		i8253.mode = Square;
.
56a
	vlong	cycwhen;	/* next fastticks a cycintr happens; 0 == infinity */
.
55c
	Lock;
	int	mode;
.
## diffname pc/i8253.c 2000/0701
## diff -e /n/emeliedump/2000/0627/sys/src/9/pc/i8253.c /n/emeliedump/2000/0701/sys/src/9/pc/i8253.c
235a
	i8253.enabled = 1;
.
207,209c
	if(i8253.enabled){
		next = cycintrnext();
		if(next != i8253.cycwhen)
			clockintrsched0(next);
	}
.
200a
int
havecycintr(void)
{
	return i8253.enabled;
}

.
55a
	int	enabled;
.
## diffname pc/i8253.c 2000/0706
## diff -e /n/emeliedump/2000/0701/sys/src/9/pc/i8253.c /n/emeliedump/2000/0706/sys/src/9/pc/i8253.c
190,191c
		if(set < Minusec)
			set = Minusec;
.
49a
	Minusec=20,		/* minimum cycles for a clock interrupt */

.
## diffname pc/i8253.c 2000/0713
## diff -e /n/emeliedump/2000/0706/sys/src/9/pc/i8253.c /n/emeliedump/2000/0713/sys/src/9/pc/i8253.c
227a

	if(!i8253.havecyc){
		clockintr(ureg, v);
		return;
	}
.
216c
	if(i8253.enabled && i8253.havecyc){
.
207c
	return i8253.havecyc && i8253.enabled;
.
74a
		i8253.havecyc = havecycleclock;
.
57a
	int	havecyc;
.
## diffname pc/i8253.c 2001/0611
## diff -e /n/emeliedump/2000/0713/sys/src/9/pc/i8253.c /n/emeliedump/2001/0611/sys/src/9/pc/i8253.c
237a

	/*
	 * If we suspend the machine and resume, the
	 * processor cycle counter gets reset.  Detect this
	 * and deal with it.
	 */
	if(now < i8253.when && i8253.when-now > 3*i8253.fastperiod)
		i8253.when = now;

.
## diffname pc/i8253.c 2001/1130
## diff -e /n/emeliedump/2001/0611/sys/src/9/pc/i8253.c /n/emeliedump/2001/1130/sys/src/9/pc/i8253.c
129c
			rdtsc(&b);
.
123c
			rdtsc(&a);
.
## diffname pc/i8253.c 2002/0221
## diff -e /n/emeliedump/2001/1130/sys/src/9/pc/i8253.c /n/emeliedump/2002/0221/sys/src/9/pc/i8253.c
262c
	i8253.fast2freq = m->cpuhz * FreqMul / Freq;
.
## diffname pc/i8253.c 2002/0314
## diff -e /n/emeliedump/2002/0221/sys/src/9/pc/i8253.c /n/emeliedump/2002/0314/sys/src/9/pc/i8253.c
262c
	i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq;
.
## diffname pc/i8253.c 2002/0404
## diff -e /n/emeliedump/2002/0314/sys/src/9/pc/i8253.c /n/emeliedump/2002/0404/sys/src/9/pc/i8253.c
147d
140d
133c

.
127d
123a
		outb(Tmode, Latch0);
.
121d
## diffname pc/i8253.c 2002/0405
## diff -e /n/emeliedump/2002/0404/sys/src/9/pc/i8253.c /n/emeliedump/2002/0405/sys/src/9/pc/i8253.c
272,273c
		*hz = Freq<<8;

	ilock(&i8253.lock1);
	outb(Tmode, Latch1);
	y = inb(T1cntr);
	y |= inb(T1cntr)<<8;

	if(y < i8253.last1)
		x = i8253.last1 - y;
	else
		x = i8253.last1 + (0xfffe - y);
	i8253.last1 = y;
	i8253.ticks1 += x>>1;
	ticks = i8253.ticks1;
	iunlock(&i8253.lock1);

	return ticks<<8;
}

/*
 *  return value and speed of timer set in arch->clockenable
 */
vlong
fastticks(uvlong *hz)
{
	return (*arch->fastclock)(hz);
.
270a
	ushort y, x;
	uvlong ticks;

.
265,266c
 *  return the total ticks of counter 1.  We shift by
 *  8 to give timesync more wriggle room for interpretation
 *  of the frequency
.
257,259c
	uvlong hz;

	i8253.when = fastticks(&hz);
	i8253.fastperiod = (hz + HZ/2) / HZ;
	i8253.fast2freq = (hz * FreqMul) / Freq;
.
250,251c
	if(i8253.timerwhen || i8253.mode != Square)
		clockintrsched0(checktimer(ureg, v));
.
236,243d
228,231c
nclockintr0++;
	/* goes with syncing in squidboy */
	if(m->havetsc)
		rdtsc(&m->lasttsc);
.
222a
int nclockintr0;
.
215,217c
	if(i8253.enabled){
		next = timernext();
		if(next != i8253.timerwhen)
.
206c
	return i8253.enabled;
.
204c
havetimer(void)
.
176c
	i8253.timerwhen = next;
.
168c
 * timerwhen is the time of the next interrupt
.
146a
	if(m->havetsc){

.
145d
138a

.
132c
	
.
127c
		outb(Tmode, Latch0);
		if(m->havetsc)
.
123a
		if(m->havetsc)
			rdtsc(&a);
.
121,122d
103a
void
guesscpuhz(int aalcycles)
{
	int cpufreq, loops, incr, x, y;
	vlong a, b;

.
102a
}
.
88,101c
	/*
	 *  set time clock
	 */
	outb(Tmode, Load1|Square);
	i8253.mode = Square;
	outb(T1cntr, 0xfe);	/* low byte */
	outb(T1cntr, 0xff);	/* high byte */

	/*
	 * Introduce a little delay to make sure the count is
	 * latched and the timer is counting down; with a fast
	 * enough processor this may not be the case.
	 * The i8254 (which this probably is) has a read-back
	 * command which can be used to make sure the counting
	 * register has been written into the counting element.
	 */
	x = (Freq/HZ);
	for(loops = 0; loops < 100000 && x >= (Freq/HZ); loops++){
		outb(Tmode, Latch0);
		x = inb(T0cntr);
		x |= inb(T0cntr)<<8;
.
80,86c
	/*
	 *  set interrupting clock for 1/HZ seconds
	 */
	outb(Tmode, Load0|Square);
	i8253.mode = Square;
	outb(T0cntr, (Freq/HZ));	/* low byte */
	outb(T0cntr, (Freq/HZ)>>8);	/* high byte */
.
74,78c
	ioalloc(T0cntr, 4, 0, "i8253");
	ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");
.
70,72c
	int loops, x;
.
68c
i8253init(void)
.
64a

	Lock	lock1;		/* mutex for the following */
	ushort	last1;		/* last value of clock 1 */
	uvlong	ticks1;		/* cumulative ticks of counter 1 */
.
62c
	vlong	timerwhen;	/* next fastticks a cycintr happens; 0 == infinity */
.
58d
23a

	Latch1=	0x40,		/* latch counter 1's value */
	Load1l=	0x50,		/* load counter 1's lsb */
	Load1m=	0x60,		/* load counter 1's msb */
	Load1=	0x70,		/* load counter 1 with 2 bytes */

.
## diffname pc/i8253.c 2002/0406
## diff -e /n/emeliedump/2002/0405/sys/src/9/pc/i8253.c /n/emeliedump/2002/0406/sys/src/9/pc/i8253.c
256a

if(i8253.last1 == 0 || i8253.last1 >= 0xffe0)
	i8253ding[1]++;
else
	i8253ding[0]++;
	
.
250d
244c
ulong i8253ding[2];

.
## diffname pc/i8253.c 2002/0409
## diff -e /n/emeliedump/2002/0406/sys/src/9/pc/i8253.c /n/emeliedump/2002/0409/sys/src/9/pc/i8253.c
314c
	return ticks<<Tickshift;
.
308,312c
		x = i8253.last + (0x1000 - y);
	i8253.last = y;
	i8253.ticks += x>>1;
	ticks = i8253.ticks;
	iunlock(&i8253);
.
305,306c
	if(y < i8253.last)
		x = i8253.last - y;
.
300,303c
	ilock(&i8253);
	outb(Tmode, Latch2);
	y = inb(T2cntr);
	y |= inb(T2cntr)<<8;
.
298c
		*hz = Freq<<Tickshift;
.
258,263d
244,245d
95,98c
	outb(Tmode, Load2|Square);
	outb(T2cntr, 0);		/* low byte */
	outb(T2cntr, 0);		/* high byte */
	x = inb(T2ctl);
	x |= T2gate;
	outb(T2ctl, x);
.
93c
	 *  enable a longer period counter to use as a clock
.
71,73c
	ushort	last;		/* last value of clock 1 */
	uvlong	ticks;		/* cumulative ticks of counter 1 */
.
54a
	Tickshift= 8,		/* increase tick wriggle room */
.
53a
	/* T2ctl bits */
	T2gate=	(1<<0),		/* enable T2 counting */
	T2spkr=	(1<<1),		/* connect T2 out to speaker */
	T2out=	(1<<5),		/* output of T2 */

.
## diffname pc/i8253.c 2002/0410
## diff -e /n/emeliedump/2002/0409/sys/src/9/pc/i8253.c /n/emeliedump/2002/0410/sys/src/9/pc/i8253.c
322c
	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;
.
316,320c
void
delay(int millisecs)
.
307c
		x = i8253.last + (0x10000 - y);
.
297c
		*hz = i8253.hz;
.
282c
	i8253.period = Freq/HZ;
	intrenable(IrqCLOCK, i8253clock, 0, BUSUNKNOWN, "clock");
.
276,280d
254,270c
	timerintr(ureg, 0);
.
252c
i8253clock(Ureg* ureg, void*)
.
248d
237,246c
		/* remember period */
		i8253.period = period;
		i8253periodset++;
		iunlock(&i8253);
.
231,235c
	/* 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 */
.
229d
208,227c
	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;
.
204,206c
	want = next>>Tickshift;
	now = i8253.ticks;	/* assuming whomever called us just did fastticks() */
.
201,202c
	ulong period;
	ulong want;
	ulong now;
.
194,199c
ulong i8253periodset;

void
i8253timerset(uvlong next)
.
191a

	i8253.hz = Freq<<Tickshift;
.
106c
	
.
102a
	i8253.period = Freq/HZ;
.
95a
	i8253.period = Freq/HZ;
.
93d
90c
	 *  enable a 1/HZ interrupt for providing scheduling interrupts
.
80a

.
71,75c
	uvlong	hz;
.
69a
	ulong	period;		/* current clock period */
.
60,64c
	Tickshift=8,		/* extra accuracy */
	MaxPeriod=Freq/HZ,
	MinPeriod=Freq/(100*HZ),
.
49,53d
## diffname pc/i8253.c 2002/0415
## diff -e /n/emeliedump/2002/0410/sys/src/9/pc/i8253.c /n/emeliedump/2002/0415/sys/src/9/pc/i8253.c
119c
	uvlong a, b;
.
## diffname pc/i8253.c 2002/0609
## diff -e /n/emeliedump/2002/0415/sys/src/9/pc/i8253.c /n/emeliedump/2002/0609/sys/src/9/pc/i8253.c
235a
}

static long
i8253timerread(Chan*, void *a, long n, vlong offset)
{
	if(n < 16)
		error("need more room");
	if(offset)
		return 0;
	return snprint(a, n, "timerset %s", i8253dotimerset ? "on" : "off");
}

static long
i8253timerwrite(Chan*, void *a, long n, vlong)
{
	if(n==3 && memcmp(a, "off", 3) == 0){
		i8253dotimerset = 0;
		outb(Tmode, Load0|Square);
		outb(T0cntr, (Freq/HZ));
		outb(T0cntr, (Freq/HZ)>>8);
		return n;
	}
	if(n==2 && memcmp(a, "on", 2) == 0){
		i8253dotimerset = 1;
		return n;
	}
	error("invalid control message");
	return -1;
}

void
i8253link(void)
{
	addarchfile("i8253timerset", 0664, i8253timerread, i8253timerwrite);
.
196a
	if(i8253dotimerset == 0)
		return;

.
188a
int i8253dotimerset = 1;
.
## diffname pc/i8253.c 2002/0703
## diff -e /n/emeliedump/2002/0609/sys/src/9/pc/i8253.c /n/emeliedump/2002/0703/sys/src/9/pc/i8253.c
213c
	/* hysteresis */
.
## diffname pc/i8253.c 2002/0710
## diff -e /n/emeliedump/2002/0703/sys/src/9/pc/i8253.c /n/emeliedump/2002/0710/sys/src/9/pc/i8253.c
325,337d
## diffname pc/i8253.c 2002/0822
## diff -e /n/emeliedump/2002/0710/sys/src/9/pc/i8253.c /n/emeliedump/2002/0822/sys/src/9/pc/i8253.c
324a

/*  
 *  performance measurement ticks.  must be low overhead.
 *  doesn't have to count over a second.
 */
ulong
perfticks(void)
{
	uvlong x;

	if(!m->havetsc)
		return m->ticks;
	rdtsc(&x);
	return x;
}
.
## diffname pc/i8253.c 2002/1218
## diff -e /n/emeliedump/2002/0822/sys/src/9/pc/i8253.c /n/emeliedump/2002/1218/sys/src/9/pc/i8253.c
219c
		outb(T0cntr, period>>8);		/* high byte */
.
214a
memmove(&phist[0], &phist[1], sizeof(phist)-sizeof(ulong));
phist[nelem(phist)-1] = period;
.
190a
ulong phist[128];

.
## diffname pc/i8253.c 2002/1219
## diff -e /n/emeliedump/2002/1218/sys/src/9/pc/i8253.c /n/emeliedump/2002/1219/sys/src/9/pc/i8253.c
223c
		outb(T0cntr, period >> 8);		/* high byte */
.
196c
	long period;
.
94d
86d
79a
	i8253.period = Freq/HZ;

.
## diffname pc/i8253.c 2003/0326
## diff -e /n/emeliedump/2002/1219/sys/src/9/pc/i8253.c /n/emeliedump/2003/0326/sys/src/9/pc/i8253.c
277d
246,273d

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.