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

2000/0627/pc/i8253.c (diff list | history)

1997/0327/sys/src/9/pc/i8253.c:98,1001998/0710/sys/src/9/pc/i8253.c:98,114 (short | long)
Add i8253read.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
{ 
	intrenable(VectorCLOCK, clockintr, 0, BUSUNKNOWN); 
} 
1998/0710    
 
Lock i8253lock; 
 
/* 
 *  return time elapsed since clock start in 
 *  10ths of nanoseconds 
 */ 
uvlong 
i8253read(uvlong *hz) 
{ 
	if(hz) 
		*hz = HZ; 
	return m->ticks; 
} 
1998/0710/sys/src/9/pc/i8253.c:99,1061998/0819/sys/src/9/pc/i8253.c:99,104 (short | long)
Remove unused i8253lock.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
	intrenable(VectorCLOCK, clockintr, 0, BUSUNKNOWN); 
} 
1998/0710    
 
Lock i8253lock; 
                 
/* 
 *  return time elapsed since clock start in 
 *  10ths of nanoseconds 
1998/0819/sys/src/9/pc/i8253.c:40,451998/0903/sys/src/9/pc/i8253.c:40,60 (short | long)
HW bug fix: wait for i8254 to start counting on fast machine.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
		outb(Tmode, Load0|Square); 
		outb(T0cntr, (Freq/HZ));	/* low byte */ 
		outb(T0cntr, (Freq/HZ)>>8);	/* high byte */ 
1998/0903    
 
		/* 
		 * 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; 
		} 
1997/0327    
	} 
 
	/* find biggest loop that doesn't wrap */ 
1998/0903/sys/src/9/pc/i8253.c:111,1171998/0910/sys/src/9/pc/i8253.c:111,117 (short | long)
Change VectorCLOCK to IrqClock.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
void 
i8253enable(void) 
{ 
	intrenable(VectorCLOCK, clockintr, 0, BUSUNKNOWN); 
1998/0910    
	intrenable(IrqCLOCK, clockintr, 0, BUSUNKNOWN); 
1997/0327    
} 
1998/0710    
 
/* 
1998/0910/sys/src/9/pc/i8253.c:27,351999/0131/sys/src/9/pc/i8253.c:27,36 (short | long)
1997/0327    
}; 
 
void 
i8253init(int aalcycles) 
1999/0131    
i8253init(int aalcycles, int havecycleclock) 
1997/0327    
{ 
	int cpufreq, loops, incr, x, y; 
1999/0131    
	vlong a, b; 
1997/0327    
	static int initialised; 
 
	if(initialised == 0){ 
1998/0910/sys/src/9/pc/i8253.c:75,841999/0131/sys/src/9/pc/i8253.c:76,89
1997/0327    
		 * 
		 */ 
		outb(Tmode, Latch0); 
1999/0131    
		if(havecycleclock) 
			rdmsr(0x10, &a); 
1997/0327    
		x = inb(T0cntr); 
		x |= inb(T0cntr)<<8; 
		aamloop(loops); 
		outb(Tmode, Latch0); 
1999/0131    
		if(havecycleclock) 
			rdmsr(0x10, &b); 
1997/0327    
		y = inb(T0cntr); 
		y |= inb(T0cntr)<<8; 
		x -= y; 
1998/0910/sys/src/9/pc/i8253.c:91,1111999/0131/sys/src/9/pc/i8253.c:96,126
1997/0327    
	} 
 
	/* 
	 *  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(). 
1999/0131    
	 *  n.b. counter goes up by 2*Freq 
1997/0327    
	 */ 
	cpufreq = loops*((aalcycles*Freq)/x); 
1999/0131    
	cpufreq = loops*((aalcycles*2*Freq)/x); 
1997/0327    
	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; 
1999/0131    
	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; 
	} 
1997/0327    
} 
 
void 
1999/0131/sys/src/9/pc/i8253.c:131,1421999/0228/sys/src/9/pc/i8253.c:131,142 (short | long)
1998/0710    
 
/* 
 *  return time elapsed since clock start in 
 *  10ths of nanoseconds 
1999/0228    
 *  100 times hz 
1998/0710    
 */ 
uvlong 
i8253read(uvlong *hz) 
{ 
	if(hz) 
		*hz = HZ; 
	return m->ticks; 
1999/0228    
		*hz = HZ*100; 
	return m->ticks*100; 
1998/0710    
} 
1999/0228/sys/src/9/pc/i8253.c:35,401999/0714/sys/src/9/pc/i8253.c:35,41 (short | long)
Use ioalloc.
rsc Fri Mar 4 12:44:25 2005
1997/0327    
 
	if(initialised == 0){ 
		initialised = 1; 
1999/0714    
		ioalloc(T0cntr, 4, 0, "i8253"); 
1997/0327    
		/* 
		 *  set clock for 1/HZ seconds 
		 */ 
1999/0714/sys/src/9/pc/i8253.c:127,1331999/0819/sys/src/9/pc/i8253.c:127,133 (short | long)
1997/0327    
void 
i8253enable(void) 
{ 
1998/0910    
	intrenable(IrqCLOCK, clockintr, 0, BUSUNKNOWN); 
1999/0819    
	intrenable(IrqCLOCK, clockintr, 0, BUSUNKNOWN, "clock"); 
1997/0327    
} 
1998/0710    
 
/* 
1999/0819/sys/src/9/pc/i8253.c:124,1332000/0621/sys/src/9/pc/i8253.c:124,140 (short | long)
1999/0131    
	} 
1997/0327    
} 
 
2000/0621    
static void 
clockintr0(Ureg* ureg, void *v) 
{ 
	loopbackintr(); 
	clockintr(ureg, v); 
} 
 
1997/0327    
void 
i8253enable(void) 
{ 
1999/0819    
	intrenable(IrqCLOCK, clockintr, 0, BUSUNKNOWN, "clock"); 
2000/0621    
	intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock"); 
1997/0327    
} 
1998/0710    
 
/* 
2000/0621/sys/src/9/pc/i8253.c:13,312000/0622/sys/src/9/pc/i8253.c:13,35 (short | long)
1997/0327    
	T0cntr=	0x40,		/* counter ports */ 
	T1cntr=	0x41,		/* ... */ 
	T2cntr=	0x42,		/* ... */ 
	Tmode=	0x43,		/* mode port */ 
2000/0622    
	Tmode=	0x43,		/* mode port (control word register) */ 
1997/0327    
 
	/* commands */ 
	Latch0=	0x00,		/* latch counter 0's value */ 
2000/0622    
	Load0l=	0x10,		/* load counter 0's lsb */ 
	Load0m=	0x20,		/* load counter 0's msb */ 
1997/0327    
	Load0=	0x30,		/* load counter 0 with 2 bytes */ 
 
	/* modes */ 
	Square=	0x36,		/* periodic square wave */ 
	Trigger= 0x30,		/* interrupt on terminal count */ 
2000/0622    
	Square=	0x6,		/* periodic square wave */ 
	Trigger= 0x0,		/* interrupt on terminal count */ 
1997/0327    
 
	Freq=	1193182,	/* Real clock frequency */ 
}; 
 
2000/0622    
static Lock	i8253lock; 
 
1997/0327    
void 
1999/0131    
i8253init(int aalcycles, int havecycleclock) 
1997/0327    
{ 
2000/0621/sys/src/9/pc/i8253.c:124,1332000/0622/sys/src/9/pc/i8253.c:128,144
1999/0131    
	} 
1997/0327    
} 
 
2000/0622    
int 
i8253readcnt(void) 
{ 
	ilock(&i8253lock); 
	iunlock(&i8253lock); 
} 
 
2000/0621    
static void 
clockintr0(Ureg* ureg, void *v) 
{ 
	loopbackintr(); 
2000/0622    
	loopbackintr(ureg); 
2000/0621    
	clockintr(ureg, v); 
} 
 
2000/0622/sys/src/9/pc/i8253.c:14,192000/0623/sys/src/9/pc/i8253.c:14,20 (short | long)
1997/0327    
	T1cntr=	0x41,		/* ... */ 
	T2cntr=	0x42,		/* ... */ 
2000/0622    
	Tmode=	0x43,		/* mode port (control word register) */ 
2000/0623    
	T2ctl=	0x61,		/* counter 2 control port */ 
1997/0327    
 
	/* commands */ 
	Latch0=	0x00,		/* latch counter 0's value */ 
2000/0622/sys/src/9/pc/i8253.c:20,342000/0623/sys/src/9/pc/i8253.c:21,62
2000/0622    
	Load0l=	0x10,		/* load counter 0's lsb */ 
	Load0m=	0x20,		/* load counter 0's msb */ 
1997/0327    
	Load0=	0x30,		/* load counter 0 with 2 bytes */ 
2000/0623    
	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 */ 
1997/0327    
 
2000/0623    
	/* 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, 
 
1997/0327    
	/* modes */ 
2000/0623    
	ModeMsk=0xe, 
2000/0622    
	Square=	0x6,		/* periodic square wave */ 
	Trigger= 0x0,		/* interrupt on terminal count */ 
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, 
 
1997/0327    
	Freq=	1193182,	/* Real clock frequency */ 
2000/0623    
 
	FreqMul=16,		/* extra accuracy in fastticks/Freq calculation; ok up to ~8ghz */ 
1997/0327    
}; 
 
2000/0622    
static Lock	i8253lock; 
2000/0623    
static struct 
{ 
	Lock	lock; 
	vlong	when;		/* next fastticks a clock interrupt should occur */ 
	long	fastperiod;	/* fastticks/hz */ 
	long	fast2freq;	/* fastticks*FreqMul/Freq */ 
}i8253; 
2000/0622    
 
1997/0327    
void 
1999/0131    
i8253init(int aalcycles, int havecycleclock) 
2000/0622/sys/src/9/pc/i8253.c:40,452000/0623/sys/src/9/pc/i8253.c:68,75
1997/0327    
	if(initialised == 0){ 
		initialised = 1; 
1999/0714    
		ioalloc(T0cntr, 4, 0, "i8253"); 
2000/0623    
		ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl"); 
 
1997/0327    
		/* 
		 *  set clock for 1/HZ seconds 
		 */ 
2000/0622/sys/src/9/pc/i8253.c:126,1442000/0623/sys/src/9/pc/i8253.c:156,239
1999/0131    
		m->cpumhz = (cpufreq + cpufreq/200)/1000000; 
		m->cpuhz = cpufreq; 
	} 
2000/0623    
 
outb(Tmode, Load0|Trigger); 
outb(T0cntr, (Freq/HZ));	/* low byte */ 
outb(T0cntr, (Freq/HZ)>>8);	/* high byte */ 
1997/0327    
} 
 
2000/0623    
static vlong lastfast; 
 
2000/0622    
int 
i8253readcnt(void) 
2000/0623    
i8253readcnt(int cntr) 
2000/0622    
{ 
	ilock(&i8253lock); 
	iunlock(&i8253lock); 
2000/0623    
	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; 
2000/0622    
} 
 
2000/0621    
static void 
clockintr0(Ureg* ureg, void *v) 
{ 
2000/0622    
	loopbackintr(ureg); 
2000/0623    
	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); 
2000/0621    
	clockintr(ureg, v); 
} 
 
2000/0622/sys/src/9/pc/i8253.c:145,1502000/0623/sys/src/9/pc/i8253.c:240,248
1997/0327    
void 
i8253enable(void) 
{ 
2000/0623    
	i8253.when = fastticks(nil); 
	i8253.fastperiod = (m->cpuhz + HZ/2) / HZ; 
	i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq; 
2000/0621    
	intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock"); 
1997/0327    
} 
1998/0710    
 
2000/0623/sys/src/9/pc/i8253.c:156,2262000/0624/sys/src/9/pc/i8253.c:156,174 (short | long)
1999/0131    
		m->cpumhz = (cpufreq + cpufreq/200)/1000000; 
		m->cpuhz = cpufreq; 
	} 
2000/0623    
                 
outb(Tmode, Load0|Trigger); 
outb(T0cntr, (Freq/HZ));	/* low byte */ 
outb(T0cntr, (Freq/HZ)>>8);	/* high byte */ 
1997/0327    
} 
 
2000/0623    
static vlong lastfast; 
2000/0624    
#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 
2000/0623    
 
2000/0622    
int 
2000/0623    
i8253readcnt(int cntr) 
2000/0622    
{ 
2000/0623    
	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; 
2000/0622    
} 
                 
2000/0621    
static void 
clockintr0(Ureg* ureg, void *v) 
{ 
2000/0624    
#ifdef SETNEXT 
2000/0623    
	vlong now; 
	long set; 
 
2000/0623/sys/src/9/pc/i8253.c:229,2372000/0624/sys/src/9/pc/i8253.c:177,185
2000/0623    
		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 */ 
2000/0624    
#endif 
2000/0623    
 
	checkcycintr(ureg, v); 
2000/0621    
	clockintr(ureg, v); 
2000/0624/sys/src/9/pc/i8253.c:52,592000/0627/sys/src/9/pc/i8253.c:52,61 (short | long)
1997/0327    
 
2000/0623    
static struct 
{ 
	Lock	lock; 
2000/0627    
	Lock; 
	int	mode; 
2000/0623    
	vlong	when;		/* next fastticks a clock interrupt should occur */ 
2000/0627    
	vlong	cycwhen;	/* next fastticks a cycintr happens; 0 == infinity */ 
2000/0623    
	long	fastperiod;	/* fastticks/hz */ 
	long	fast2freq;	/* fastticks*FreqMul/Freq */ 
}i8253; 
2000/0624/sys/src/9/pc/i8253.c:74,792000/0627/sys/src/9/pc/i8253.c:76,82
1997/0327    
		 *  set clock for 1/HZ seconds 
		 */ 
		outb(Tmode, Load0|Square); 
2000/0627    
		i8253.mode = Square; 
1997/0327    
		outb(T0cntr, (Freq/HZ));	/* low byte */ 
		outb(T0cntr, (Freq/HZ)>>8);	/* high byte */ 
1998/0903    
 
2000/0624/sys/src/9/pc/i8253.c:158,1882000/0627/sys/src/9/pc/i8253.c:161,230
1999/0131    
	} 
1997/0327    
} 
 
2000/0624    
#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 
2000/0623    
                 
2000/0627    
/* 
 * schedule the next interrupt 
 * cycwhen is the next time for the cycle counter routines 
 */ 
2000/0621    
static void 
clockintr0(Ureg* ureg, void *v) 
2000/0627    
clockintrsched0(vlong next) 
2000/0621    
{ 
2000/0624    
#ifdef SETNEXT 
2000/0623    
	vlong now; 
	long set; 
 
2000/0627    
	i8253.cycwhen = next; 
	if(i8253.mode == Square && next == 0) 
		return; 
 
2000/0623    
	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 */ 
	outb(T0cntr, set);	/* low byte */ 
	outb(T0cntr, set>>8);	/* high byte */ 
2000/0624    
#endif 
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--; 
		} 
		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 */ 
	} 
} 
2000/0623    
 
	checkcycintr(ureg, v); 
2000/0621    
	clockintr(ureg, v); 
2000/0627    
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)); 
2000/0621    
} 
 
1997/0327    
void 
2000/0627/sys/src/9/pc/i8253.c:53,582000/0701/sys/src/9/pc/i8253.c:53,59 (short | long)
2000/0623    
static struct 
{ 
2000/0627    
	Lock; 
2000/0701    
	int	enabled; 
2000/0627    
	int	mode; 
2000/0623    
	vlong	when;		/* next fastticks a clock interrupt should occur */ 
2000/0627    
	vlong	cycwhen;	/* next fastticks a cycintr happens; 0 == infinity */ 
2000/0627/sys/src/9/pc/i8253.c:198,2032000/0701/sys/src/9/pc/i8253.c:199,210
2000/0627    
	} 
} 
2000/0623    
 
2000/0701    
int 
havecycintr(void) 
{ 
	return i8253.enabled; 
} 
 
2000/0627    
void 
clockintrsched(void) 
{ 
2000/0627/sys/src/9/pc/i8253.c:204,2122000/0701/sys/src/9/pc/i8253.c:211,221
2000/0627    
	vlong next; 
 
	ilock(&i8253); 
	next = cycintrnext(); 
	if(next != i8253.cycwhen) 
		clockintrsched0(next); 
2000/0701    
	if(i8253.enabled){ 
		next = cycintrnext(); 
		if(next != i8253.cycwhen) 
			clockintrsched0(next); 
	} 
2000/0627    
	iunlock(&i8253); 
} 
 
2000/0627/sys/src/9/pc/i8253.c:233,2382000/0701/sys/src/9/pc/i8253.c:242,248
2000/0623    
	i8253.when = fastticks(nil); 
	i8253.fastperiod = (m->cpuhz + HZ/2) / HZ; 
	i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq; 
2000/0701    
	i8253.enabled = 1; 
2000/0621    
	intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock"); 
1997/0327    
} 
1998/0710    
 
2000/0701/sys/src/9/pc/i8253.c:47,522000/0706/sys/src/9/pc/i8253.c:47,54 (short | long)
2000/0623    
 
1997/0327    
	Freq=	1193182,	/* Real clock frequency */ 
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 */ 
1997/0327    
}; 
 
2000/0701/sys/src/9/pc/i8253.c:187,1942000/0706/sys/src/9/pc/i8253.c:189,196
2000/0627    
			i8253.mode = Trigger; 
			set--; 
		} 
		if(set < 3) 
			set = 5; 
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){ 
2000/0706/sys/src/9/pc/i8253.c:55,602000/0713/sys/src/9/pc/i8253.c:55,61 (short | long)
2000/0623    
static struct 
{ 
2000/0627    
	Lock; 
2000/0713    
	int	havecyc; 
2000/0701    
	int	enabled; 
2000/0627    
	int	mode; 
2000/0623    
	vlong	when;		/* next fastticks a clock interrupt should occur */ 
2000/0706/sys/src/9/pc/i8253.c:72,772000/0713/sys/src/9/pc/i8253.c:73,79
1997/0327    
 
	if(initialised == 0){ 
		initialised = 1; 
2000/0713    
		i8253.havecyc = havecycleclock; 
1999/0714    
		ioalloc(T0cntr, 4, 0, "i8253"); 
2000/0623    
		ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl"); 
 
2000/0706/sys/src/9/pc/i8253.c:204,2102000/0713/sys/src/9/pc/i8253.c:206,212
2000/0701    
int 
havecycintr(void) 
{ 
	return i8253.enabled; 
2000/0713    
	return i8253.havecyc && i8253.enabled; 
2000/0701    
} 
 
2000/0627    
void 
2000/0706/sys/src/9/pc/i8253.c:213,2192000/0713/sys/src/9/pc/i8253.c:215,221
2000/0627    
	vlong next; 
 
	ilock(&i8253); 
2000/0701    
	if(i8253.enabled){ 
2000/0713    
	if(i8253.enabled && i8253.havecyc){ 
2000/0701    
		next = cycintrnext(); 
		if(next != i8253.cycwhen) 
			clockintrsched0(next); 
2000/0706/sys/src/9/pc/i8253.c:225,2302000/0713/sys/src/9/pc/i8253.c:227,237
2000/0627    
clockintr0(Ureg* ureg, void *v) 
{ 
	vlong now, when; 
2000/0713    
 
	if(!i8253.havecyc){ 
		clockintr(ureg, v); 
		return; 
	} 
2000/0627    
 
	now = fastticks(nil); 
	when = i8253.when; 
2000/0713/sys/src/9/pc/i8253.c:235,2402001/0611/sys/src/9/pc/i8253.c:235,249 (short | long)
2000/0627    
 
	now = fastticks(nil); 
	when = i8253.when; 
2001/0611    
 
	/* 
	 * 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; 
 
2000/0627    
	if(now >= i8253.when){ 
		clockintr(ureg, v); 
		do 
2001/0611/sys/src/9/pc/i8253.c:120,1322001/1130/sys/src/9/pc/i8253.c:120,132 (short | long)
1997/0327    
		 */ 
		outb(Tmode, Latch0); 
1999/0131    
		if(havecycleclock) 
			rdmsr(0x10, &a); 
2001/1130    
			rdtsc(&a); 
1997/0327    
		x = inb(T0cntr); 
		x |= inb(T0cntr)<<8; 
		aamloop(loops); 
		outb(Tmode, Latch0); 
1999/0131    
		if(havecycleclock) 
			rdmsr(0x10, &b); 
2001/1130    
			rdtsc(&b); 
1997/0327    
		y = inb(T0cntr); 
		y |= inb(T0cntr)<<8; 
		x -= y; 
2001/1130/sys/src/9/pc/i8253.c:259,2652002/0221/sys/src/9/pc/i8253.c:259,265 (short | long)
1997/0327    
{ 
2000/0623    
	i8253.when = fastticks(nil); 
	i8253.fastperiod = (m->cpuhz + HZ/2) / HZ; 
	i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq; 
2002/0221    
	i8253.fast2freq = m->cpuhz * FreqMul / Freq; 
2000/0701    
	i8253.enabled = 1; 
2000/0621    
	intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock"); 
1997/0327    
} 
2002/0221/sys/src/9/pc/i8253.c:259,2652002/0314/sys/src/9/pc/i8253.c:259,265 (short | long)
1997/0327    
{ 
2000/0623    
	i8253.when = fastticks(nil); 
	i8253.fastperiod = (m->cpuhz + HZ/2) / HZ; 
2002/0221    
	i8253.fast2freq = m->cpuhz * FreqMul / Freq; 
2002/0314    
	i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq; 
2000/0701    
	i8253.enabled = 1; 
2000/0621    
	intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock"); 
1997/0327    
} 
2002/0314/sys/src/9/pc/i8253.c:118,1362002/0404/sys/src/9/pc/i8253.c:118,135 (short | long)
1997/0327    
		 *  prefetch buffer. 
		 * 
		 */ 
		outb(Tmode, Latch0); 
1999/0131    
		if(havecycleclock) 
2001/1130    
			rdtsc(&a); 
2002/0404    
		outb(Tmode, Latch0); 
1997/0327    
		x = inb(T0cntr); 
		x |= inb(T0cntr)<<8; 
		aamloop(loops); 
		outb(Tmode, Latch0); 
1999/0131    
		if(havecycleclock) 
2001/1130    
			rdtsc(&b); 
1997/0327    
		y = inb(T0cntr); 
		y |= inb(T0cntr)<<8; 
		x -= y; 
	                 
2002/0404    
 
1997/0327    
		if(x < 0) 
			x += Freq/HZ; 
 
2002/0314/sys/src/9/pc/i8253.c:137,1432002/0404/sys/src/9/pc/i8253.c:136,141
1997/0327    
		if(x > Freq/(3*HZ)) 
			break; 
	} 
                 
	/* 
 	 *  figure out clock frequency and a loop multiplier for delay(). 
1999/0131    
	 *  n.b. counter goes up by 2*Freq 
2002/0314/sys/src/9/pc/i8253.c:144,1502002/0404/sys/src/9/pc/i8253.c:142,147
1997/0327    
	 */ 
1999/0131    
	cpufreq = loops*((aalcycles*2*Freq)/x); 
1997/0327    
	m->loopconst = (cpufreq/1000)/aalcycles;	/* AAM+LOOP's for 1 ms */ 
                 
1999/0131    
	if(havecycleclock){ 
 
		/* counter goes up by 2*Freq */ 
2002/0404/sys/src/9/pc/i8253.c:21,262002/0405/sys/src/9/pc/i8253.c:21,32 (short | long)
2000/0622    
	Load0l=	0x10,		/* load counter 0's lsb */ 
	Load0m=	0x20,		/* load counter 0's msb */ 
1997/0327    
	Load0=	0x30,		/* load counter 0 with 2 bytes */ 
2002/0405    
 
	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 */ 
 
2000/0623    
	Latch2=	0x80,		/* latch counter 2's value */ 
	Load2l=	0x90,		/* load counter 2's lsb */ 
	Load2m=	0xa0,		/* load counter 2's msb */ 
2002/0404/sys/src/9/pc/i8253.c:55,1062002/0405/sys/src/9/pc/i8253.c:61,124
2000/0623    
static struct 
{ 
2000/0627    
	Lock; 
2000/0713    
	int	havecyc; 
2000/0701    
	int	enabled; 
2000/0627    
	int	mode; 
2000/0623    
	vlong	when;		/* next fastticks a clock interrupt should occur */ 
2000/0627    
	vlong	cycwhen;	/* next fastticks a cycintr happens; 0 == infinity */ 
2002/0405    
	vlong	timerwhen;	/* next fastticks a cycintr happens; 0 == infinity */ 
2000/0623    
	long	fastperiod;	/* fastticks/hz */ 
	long	fast2freq;	/* fastticks*FreqMul/Freq */ 
2002/0405    
 
	Lock	lock1;		/* mutex for the following */ 
	ushort	last1;		/* last value of clock 1 */ 
	uvlong	ticks1;		/* cumulative ticks of counter 1 */ 
2000/0623    
}i8253; 
2000/0622    
 
1997/0327    
void 
1999/0131    
i8253init(int aalcycles, int havecycleclock) 
2002/0405    
i8253init(void) 
1997/0327    
{ 
	int cpufreq, loops, incr, x, y; 
1999/0131    
	vlong a, b; 
1997/0327    
	static int initialised; 
2002/0405    
	int loops, x; 
1997/0327    
 
	if(initialised == 0){ 
		initialised = 1; 
2000/0713    
		i8253.havecyc = havecycleclock; 
1999/0714    
		ioalloc(T0cntr, 4, 0, "i8253"); 
2000/0623    
		ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl"); 
2002/0405    
	ioalloc(T0cntr, 4, 0, "i8253"); 
	ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl"); 
2000/0623    
 
1997/0327    
		/* 
		 *  set clock for 1/HZ seconds 
		 */ 
		outb(Tmode, Load0|Square); 
2000/0627    
		i8253.mode = Square; 
1997/0327    
		outb(T0cntr, (Freq/HZ));	/* low byte */ 
		outb(T0cntr, (Freq/HZ)>>8);	/* high byte */ 
2002/0405    
	/* 
	 *  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 */ 
1998/0903    
 
		/* 
		 * 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; 
		} 
2002/0405    
	/* 
	 *  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; 
1997/0327    
	} 
2002/0405    
} 
1997/0327    
 
2002/0405    
void 
guesscpuhz(int aalcycles) 
{ 
	int cpufreq, loops, incr, x, y; 
	vlong a, b; 
 
1997/0327    
	/* find biggest loop that doesn't wrap */ 
	incr = 16000000/(aalcycles*HZ*2); 
	x = 2000; 
2002/0404/sys/src/9/pc/i8253.c:118,1352002/0405/sys/src/9/pc/i8253.c:136,154
1997/0327    
		 *  prefetch buffer. 
		 * 
		 */ 
1999/0131    
		if(havecycleclock) 
2001/1130    
			rdtsc(&a); 
2002/0404    
		outb(Tmode, Latch0); 
2002/0405    
		if(m->havetsc) 
			rdtsc(&a); 
1997/0327    
		x = inb(T0cntr); 
		x |= inb(T0cntr)<<8; 
		aamloop(loops); 
1999/0131    
		if(havecycleclock) 
2002/0405    
		outb(Tmode, Latch0); 
		if(m->havetsc) 
2001/1130    
			rdtsc(&b); 
1997/0327    
		y = inb(T0cntr); 
		y |= inb(T0cntr)<<8; 
		x -= y; 
2002/0404    
                 
2002/0405    
	 
1997/0327    
		if(x < 0) 
			x += Freq/HZ; 
 
2002/0404/sys/src/9/pc/i8253.c:136,1412002/0405/sys/src/9/pc/i8253.c:155,161
1997/0327    
		if(x > Freq/(3*HZ)) 
			break; 
	} 
2002/0405    
 
1997/0327    
	/* 
 	 *  figure out clock frequency and a loop multiplier for delay(). 
1999/0131    
	 *  n.b. counter goes up by 2*Freq 
2002/0404/sys/src/9/pc/i8253.c:142,1492002/0405/sys/src/9/pc/i8253.c:162,170
1997/0327    
	 */ 
1999/0131    
	cpufreq = loops*((aalcycles*2*Freq)/x); 
1997/0327    
	m->loopconst = (cpufreq/1000)/aalcycles;	/* AAM+LOOP's for 1 ms */ 
1999/0131    
	if(havecycleclock){ 
 
2002/0405    
	if(m->havetsc){ 
 
1999/0131    
		/* counter goes up by 2*Freq */ 
		b = (b-a)<<1; 
		b *= Freq; 
2002/0404/sys/src/9/pc/i8253.c:165,1712002/0405/sys/src/9/pc/i8253.c:186,192
1997/0327    
 
2000/0627    
/* 
 * schedule the next interrupt 
 * cycwhen is the next time for the cycle counter routines 
2002/0405    
 * timerwhen is the time of the next interrupt 
2000/0627    
 */ 
2000/0621    
static void 
2000/0627    
clockintrsched0(vlong next) 
2002/0404/sys/src/9/pc/i8253.c:173,1792002/0405/sys/src/9/pc/i8253.c:194,200
2000/0623    
	vlong now; 
	long set; 
 
2000/0627    
	i8253.cycwhen = next; 
2002/0405    
	i8253.timerwhen = next; 
2000/0627    
	if(i8253.mode == Square && next == 0) 
		return; 
 
2002/0404/sys/src/9/pc/i8253.c:201,2092002/0405/sys/src/9/pc/i8253.c:222,230
2000/0627    
} 
2000/0623    
 
2000/0701    
int 
havecycintr(void) 
2002/0405    
havetimer(void) 
2000/0701    
{ 
2000/0713    
	return i8253.havecyc && i8253.enabled; 
2002/0405    
	return i8253.enabled; 
2000/0701    
} 
 
2000/0627    
void 
2002/0404/sys/src/9/pc/i8253.c:212,2462002/0405/sys/src/9/pc/i8253.c:233,260
2000/0627    
	vlong next; 
 
	ilock(&i8253); 
2000/0713    
	if(i8253.enabled && i8253.havecyc){ 
2000/0701    
		next = cycintrnext(); 
		if(next != i8253.cycwhen) 
2002/0405    
	if(i8253.enabled){ 
		next = timernext(); 
		if(next != i8253.timerwhen) 
2000/0701    
			clockintrsched0(next); 
	} 
2000/0627    
	iunlock(&i8253); 
} 
 
2002/0405    
int nclockintr0; 
2000/0627    
static void 
clockintr0(Ureg* ureg, void *v) 
{ 
	vlong now, when; 
2000/0713    
 
	if(!i8253.havecyc){ 
		clockintr(ureg, v); 
		return; 
	} 
2002/0405    
nclockintr0++; 
	/* goes with syncing in squidboy */ 
	if(m->havetsc) 
		rdtsc(&m->lasttsc); 
2000/0627    
 
	now = fastticks(nil); 
	when = i8253.when; 
2001/0611    
 
	/* 
	 * 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; 
                 
2000/0627    
	if(now >= i8253.when){ 
		clockintr(ureg, v); 
		do 
2002/0404/sys/src/9/pc/i8253.c:247,2742002/0405/sys/src/9/pc/i8253.c:261,318
2000/0627    
			i8253.when += i8253.fastperiod; 
		while(i8253.when < now); 
	} 
	if(i8253.cycwhen || i8253.mode != Square) 
		clockintrsched0(checkcycintr(ureg, v)); 
2002/0405    
	if(i8253.timerwhen || i8253.mode != Square) 
		clockintrsched0(checktimer(ureg, v)); 
2000/0621    
} 
 
1997/0327    
void 
i8253enable(void) 
{ 
2000/0623    
	i8253.when = fastticks(nil); 
	i8253.fastperiod = (m->cpuhz + HZ/2) / HZ; 
2002/0314    
	i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq; 
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"); 
1997/0327    
} 
1998/0710    
 
/* 
 *  return time elapsed since clock start in 
1999/0228    
 *  100 times hz 
2002/0405    
 *  return the total ticks of counter 1.  We shift by 
 *  8 to give timesync more wriggle room for interpretation 
 *  of the frequency 
1998/0710    
 */ 
uvlong 
i8253read(uvlong *hz) 
{ 
2002/0405    
	ushort y, x; 
	uvlong ticks; 
 
1998/0710    
	if(hz) 
1999/0228    
		*hz = HZ*100; 
	return m->ticks*100; 
2002/0405    
		*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); 
1998/0710    
} 
2002/0405/sys/src/9/pc/i8253.c:241,2532002/0406/sys/src/9/pc/i8253.c:241,253 (short | long)
2000/0627    
	iunlock(&i8253); 
} 
 
2002/0405    
int nclockintr0; 
2002/0406    
ulong i8253ding[2]; 
 
2000/0627    
static void 
clockintr0(Ureg* ureg, void *v) 
{ 
	vlong now, when; 
2000/0713    
 
2002/0405    
nclockintr0++; 
	/* goes with syncing in squidboy */ 
	if(m->havetsc) 
		rdtsc(&m->lasttsc); 
2002/0405/sys/src/9/pc/i8253.c:254,2592002/0406/sys/src/9/pc/i8253.c:254,265
2000/0627    
 
	now = fastticks(nil); 
	when = i8253.when; 
2002/0406    
 
if(i8253.last1 == 0 || i8253.last1 >= 0xffe0) 
	i8253ding[1]++; 
else 
	i8253ding[0]++; 
	 
2001/0611    
 
2000/0627    
	if(now >= i8253.when){ 
		clockintr(ureg, v); 
2002/0406/sys/src/9/pc/i8253.c:51,572002/0409/sys/src/9/pc/i8253.c:51,63 (short | long)
2000/0623    
	C2speak=0x2, 
	C2out=	0x10, 
 
2002/0409    
	/* T2ctl bits */ 
	T2gate=	(1<<0),		/* enable T2 counting */ 
	T2spkr=	(1<<1),		/* connect T2 out to speaker */ 
	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 */ 
 
2002/0406/sys/src/9/pc/i8253.c:68,762002/0409/sys/src/9/pc/i8253.c:74,81
2000/0623    
	long	fastperiod;	/* fastticks/hz */ 
	long	fast2freq;	/* fastticks*FreqMul/Freq */ 
2002/0405    
 
	Lock	lock1;		/* mutex for the following */ 
	ushort	last1;		/* last value of clock 1 */ 
	uvlong	ticks1;		/* cumulative ticks of counter 1 */ 
2002/0409    
	ushort	last;		/* last value of clock 1 */ 
	uvlong	ticks;		/* cumulative ticks of counter 1 */ 
2000/0623    
}i8253; 
2000/0622    
 
1997/0327    
void 
2002/0406/sys/src/9/pc/i8253.c:90,1012002/0409/sys/src/9/pc/i8253.c:95,108
2002/0405    
	outb(T0cntr, (Freq/HZ)>>8);	/* high byte */ 
1998/0903    
 
2002/0405    
	/* 
	 *  set time clock 
2002/0409    
	 *  enable a longer period counter to use as a clock 
2002/0405    
	 */ 
	outb(Tmode, Load1|Square); 
	i8253.mode = Square; 
	outb(T1cntr, 0xfe);	/* low byte */ 
	outb(T1cntr, 0xff);	/* high byte */ 
2002/0409    
	outb(Tmode, Load2|Square); 
	outb(T2cntr, 0);		/* low byte */ 
	outb(T2cntr, 0);		/* high byte */ 
	x = inb(T2ctl); 
	x |= T2gate; 
	outb(T2ctl, x); 
2002/0405    
 
	/* 
	 * Introduce a little delay to make sure the count is 
2002/0406/sys/src/9/pc/i8253.c:241,2482002/0409/sys/src/9/pc/i8253.c:248,253
2000/0627    
	iunlock(&i8253); 
} 
 
2002/0406    
ulong i8253ding[2]; 
                 
2000/0627    
static void 
clockintr0(Ureg* ureg, void *v) 
{ 
2002/0406/sys/src/9/pc/i8253.c:255,2662002/0409/sys/src/9/pc/i8253.c:260,265
2000/0627    
	now = fastticks(nil); 
	when = i8253.when; 
2002/0406    
 
if(i8253.last1 == 0 || i8253.last1 >= 0xffe0) 
	i8253ding[1]++; 
else 
	i8253ding[0]++; 
	                 
2001/0611    
                 
2000/0627    
	if(now >= i8253.when){ 
		clockintr(ureg, v); 
		do 
2002/0406/sys/src/9/pc/i8253.c:295,3172002/0409/sys/src/9/pc/i8253.c:294,316
2002/0405    
	uvlong ticks; 
 
1998/0710    
	if(hz) 
2002/0405    
		*hz = Freq<<8; 
2002/0409    
		*hz = Freq<<Tickshift; 
2002/0405    
 
	ilock(&i8253.lock1); 
	outb(Tmode, Latch1); 
	y = inb(T1cntr); 
	y |= inb(T1cntr)<<8; 
2002/0409    
	ilock(&i8253); 
	outb(Tmode, Latch2); 
	y = inb(T2cntr); 
	y |= inb(T2cntr)<<8; 
2002/0405    
 
	if(y < i8253.last1) 
		x = i8253.last1 - y; 
2002/0409    
	if(y < i8253.last) 
		x = i8253.last - y; 
2002/0405    
	else 
		x = i8253.last1 + (0xfffe - y); 
	i8253.last1 = y; 
	i8253.ticks1 += x>>1; 
	ticks = i8253.ticks1; 
	iunlock(&i8253.lock1); 
2002/0409    
		x = i8253.last + (0x1000 - y); 
	i8253.last = y; 
	i8253.ticks += x>>1; 
	ticks = i8253.ticks; 
	iunlock(&i8253); 
2002/0405    
 
	return ticks<<8; 
2002/0409    
	return ticks<<Tickshift; 
2002/0405    
} 
 
/* 
2002/0409/sys/src/9/pc/i8253.c:46,562002/0410/sys/src/9/pc/i8253.c:46,51 (short | long)
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    
} 
Too many diffs (26 > 25). Stopping.


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