~kris/9p

9hist

e165207c4ae0d990ccc83ab94779cb4087697a8a — David du Colombier 26 years ago 232fb58
Plan 9 from Bell Labs 2000-06-23
4 files changed, 202 insertions(+), 7 deletions(-)

A pc/cycintr.c
M pc/dat.h
M pc/fns.h
M pc/i8253.c
A pc/cycintr.c => pc/cycintr.c +82 -0
@@ 0,0 1,82 @@
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"


static struct
{
	Lock;
	vlong	when;			/* next scheduled interrupt time */
	Cycintr	*ci;
}cycintrs;

static void
cycsched(void)
{
}

void
checkcycintr(Ureg *u, void*)
{
	Cycintr *ci;

	ilock(&cycintrs);
	while(ci = cycintrs.ci){
		if(ci->when > fastticks(nil))
			break;
		cycintrs.ci = ci->next;
		iunlock(&cycintrs);
		(*ci->f)(u, ci);
		ilock(&cycintrs);
	}
	cycsched();
	iunlock(&cycintrs);
}

void
cycintradd(Cycintr *nci)
{
	Cycintr *ci, **last;

	ilock(&cycintrs);
	last = &cycintrs.ci;
	while(ci = *last){
		if(ci == nci){
			*last = ci->next;
			break;
		}
		last = &ci->next;
	}

	last = &cycintrs.ci;
	while(ci = *last){
		if(ci->when > nci->when)
			break;
		last = &ci->next;
	}
	nci->next = *last;
	*last = nci;
	if(nci->when < cycintrs.when)
		cycsched();
	iunlock(&cycintrs);
}

void
cycintrdel(Cycintr *dci)
{
	Cycintr *ci, **last;

	ilock(&cycintrs);
	last = &cycintrs.ci;
	while(ci = *last){
		if(ci == dci){
			*last = ci->next;
			break;
		}
		last = &ci->next;
	}
	iunlock(&cycintrs);
}

M pc/dat.h => pc/dat.h +13 -0
@@ 194,6 194,19 @@ struct Mach
	int	stack[1];
};

typedef struct Cycintr	Cycintr;

/*
 * fasttick timer interrupts
 */
struct Cycintr
{
	vlong	when;			/* fastticks when f should be called */
	void	(*f)(Ureg*, Cycintr*);
	void	*a;
	Cycintr	*next;
};

/*
 * Fake kmap
 */

M pc/fns.h => pc/fns.h +3 -1
@@ 1,6 1,8 @@
#include "../port/portfns.h"

void	loopbackintr(Ureg*);
void	checkcycintr(Ureg*, void*);
void	cycintradd(Cycintr*);
void	cycintrdel(Cycintr*);


void	aamloop(int);

M pc/i8253.c => pc/i8253.c +104 -6
@@ 14,21 14,49 @@ enum
	T1cntr=	0x41,		/* ... */
	T2cntr=	0x42,		/* ... */
	Tmode=	0x43,		/* mode port (control word register) */
	T2ctl=	0x61,		/* counter 2 control port */

	/* commands */
	Latch0=	0x00,		/* latch counter 0's value */
	Load0l=	0x10,		/* load counter 0's lsb */
	Load0m=	0x20,		/* load counter 0's msb */
	Load0=	0x30,		/* load counter 0 with 2 bytes */
	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 */

	/* 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,

	/* modes */
	ModeMsk=0xe,
	Square=	0x6,		/* periodic square wave */
	Trigger= 0x0,		/* interrupt on terminal count */
	Trigger=0x0,		/* interrupt on terminal count */
	Sstrobe=0x8,		/* software triggered strobe */

	/* counter 2 controls */
	C2gate=	0x1,
	C2speak=0x2,
	C2out=	0x10,

	Freq=	1193182,	/* Real clock frequency */

	FreqMul=16,		/* extra accuracy in fastticks/Freq calculation; ok up to ~8ghz */
};

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

void
i8253init(int aalcycles, int havecycleclock)


@@ 40,6 68,8 @@ i8253init(int aalcycles, int havecycleclock)
	if(initialised == 0){
		initialised = 1;
		ioalloc(T0cntr, 4, 0, "i8253");
		ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");

		/*
		 *  set clock for 1/HZ seconds
		 */


@@ 126,25 156,93 @@ i8253init(int aalcycles, int havecycleclock)
		m->cpumhz = (cpufreq + cpufreq/200)/1000000;
		m->cpuhz = cpufreq;
	}

outb(Tmode, Load0|Trigger);
outb(T0cntr, (Freq/HZ));	/* low byte */
outb(T0cntr, (Freq/HZ)>>8);	/* high byte */
}

static vlong lastfast;

int
i8253readcnt(void)
i8253readcnt(int cntr)
{
	ilock(&i8253lock);
	iunlock(&i8253lock);
	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;
}

static void
clockintr0(Ureg* ureg, void *v)
{
	loopbackintr(ureg);
	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);
	clockintr(ureg, v);
}

void
i8253enable(void)
{
	i8253.when = fastticks(nil);
	i8253.fastperiod = (m->cpuhz + HZ/2) / HZ;
	i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq;
	intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock");
}