~kris/9p

9hist

37fa96378cc4e547a236cce9bfa67e3994dfc7f6 — David du Colombier 24 years ago 7f34cfa
Plan 9 from Bell Labs 2002-04-05
M alphapc/cycintr.c => alphapc/cycintr.c +3 -3
@@ 6,18 6,18 @@
#include "io.h"

int
havecycintr(void)
havetimer(void)
{
	return 0;
}

void
cycintradd(Cycintr *)
timeradd(Timer *)
{
}

void
cycintrdel(Cycintr *)
timerdel(Timer *)
{
}


M alphapc/dat.h => alphapc/dat.h +4 -4
@@ 1,5 1,5 @@
typedef struct Conf	Conf;
typedef struct Cycintr	Cycintr;
typedef struct Timer	Timer;
typedef struct FPsave	FPsave;
typedef struct ISAConf	ISAConf;
typedef struct Label	Label;


@@ 252,10 252,10 @@ struct DevConf
/*
 * fasttick timer interrupts (Dummy for now)
 */
struct Cycintr
struct Timer
{
	vlong	when;			/* fastticks when f should be called */
	void	(*f)(Ureg*, Cycintr*);
	void	(*f)(Ureg*, Timer*);
	void	*a;
	Cycintr	*next;
	Timer	*next;
};

M alphapc/fns.h => alphapc/fns.h +3 -3
@@ 13,8 13,8 @@ int		cistrcmp(char*, char*);
int		cistrncmp(char*, char*, int);
void		cpuidprint(void);
void		cserve(ulong, ulong);
void		cycintradd(Cycintr *);
void		cycintrdel(Cycintr *);
void		timeradd(Timer *);
void		timerdel(Timer *);
int	dmacount(int);
int	dmadone(int);
void	dmaend(int);


@@ 35,7 35,7 @@ char		*getconf(char*);
ulong	getfcr(void);
ulong	getstatus(void);
void		gotopc(ulong);
int		havecycintr(void);
int		havetimer(void);
int		i8042auxcmd(int);
void		i8042auxenable(void (*)(int, int));
void		i8042reset(void);

M bitsy/clock.c => bitsy/clock.c +28 -5
@@ 21,6 21,12 @@ static int clockinited;

static void	clockintr(Ureg*, void*);

enum
{
	Minfreq = ClockFreq/HZ,		/* At least one interrupt per HZ (10 ms) */
	Maxfreq = ClockFreq/10000,	/* At most one interrupt every 100 µs */
};

void
clockpower(int on)
{


@@ 61,6 67,8 @@ clockinit(void)
	/* post interrupt 1/HZ secs from now */
	timerregs->osmr[0] = timerregs->oscr + ClockFreq/HZ;

	timersinit();

	clockinited = 1;
}



@@ 84,17 92,32 @@ fastticks(uvlong *hz)
	return high+x;
}

void
timerset(vlong v)
{
	ulong when;	/* Must be unsigned! */

	if (v == 0LL)
		when = timerregs->oscr + Minfreq;
	else {
		when = v;

		/* post next interrupt: calculate # of tics from now */
		when = when - timerregs->oscr - Maxfreq;
		if (when - timerregs->oscr > Minfreq)
			when = timerregs->oscr + Maxfreq;
	}
	timerregs->osmr[0] = when;
}

static void
clockintr(Ureg *ureg, void*)
{

	/* reset previous interrupt */
	timerregs->ossr |= 1<<0;

	/* post interrupt 1/HZ secs from now */
	timerregs->osmr[0] = timerregs->oscr + ClockFreq/HZ;

	drawactive(0);	/* screen saver */
	portclock(ureg);
	timerset(timerintr(ureg, nil));
}

void

M bitsy/dat.h => bitsy/dat.h +13 -12
@@ 1,6 1,5 @@
typedef struct Cisdat 		Cisdat;
typedef struct Conf		Conf;
typedef struct Cycintr		Cycintr;
typedef struct FPU		FPU;
typedef struct FPenv		FPenv;
typedef struct FPsave		FPsave;


@@ 17,6 16,7 @@ typedef struct PCMconftab	PCMconftab;
typedef struct PhysUart		PhysUart;
typedef struct PMMU		PMMU;
typedef struct Proc		Proc;
typedef struct Timer		Timer;
typedef struct Uart		Uart;
typedef struct Ureg		Ureg;
typedef struct Vctl		Vctl;


@@ 155,17 155,6 @@ struct Mach
};

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

/*
 * Fake kmap since we direct map dram
 */
typedef void		KMap;


@@ 273,3 262,15 @@ struct DevConf
	ulong	interrupt;	/* interrupt number */
	char		*type;	/* card type, mallocated */
};

/*
 * Timer interrupts
 */
struct Timer
{
	vlong	when;			/* fastticks when f should be called */
	vlong	period;			/* non-zero for recurring periodic timers */
	void		(*f)(Ureg*, Timer*);	/* function to call */
	void		*a;				/* User parameter */
	Timer	*next;
};

M bitsy/fns.h => bitsy/fns.h +8 -4
@@ 1,5 1,6 @@
#include "../port/portfns.h"

void	addclock0link(void (*)(void));
void	audiopower(int);
void	audioamppower(int);
void	audioicpower(int);


@@ 7,16 8,14 @@ void	cacheflush(void);
void	cachewb(void);
void	cachewbaddr(void*);
void	cachewbregion(ulong, int);
void	clockintrsched(void);	/* to be deleted */
void	coma(ulong);
void	dcacheinvalidate(void);
int	cistrcmp(char*, char*);
int	cistrncmp(char*, char*, int);
void	clockinit(void);
void	clockpower(int);
void	clockintrsched(void);
#define	coherence()
void	cycintradd(Cycintr *);
void	cycintrdel(Cycintr *);
#define	dcflush(a, b)
void	delay(int);
void	µdelay(ulong);


@@ 43,7 42,7 @@ void*	getlink(void);
ulong	getsp(void);
void	gpiointrenable(ulong, int, void (*)(Ureg*, void*), void*, char*);
void	h3650uartsetup(void);
int	havecycintr(void);
int	havetimer(void);
void	icacheinvalidate(void);
void	idle(void);
void	idlehands(void);


@@ 101,6 100,11 @@ int	screenprint(char*, ...);			/* debugging */
void	serialµcputs(uchar *str, int n);
void	setr13(int, ulong*);
uchar*	tarlookup(uchar*, char*, int*);
void	timersinit(void);
void	timeradd(Timer*);
void	timerdel(Timer*);
vlong	timerintr(Ureg *, void*);
void	timerset(vlong);
void	touser(void*);
void	trapdump(char *tag);
void	trapinit(void);

M ip/tcp.c => ip/tcp.c +34 -34
@@ 16,9 16,9 @@ enum
	TCP_HDRSIZE	= 20,
	TCP_TCBPHDRSZ	= 40,
	TCP_PKT		= TCP_IPLEN+TCP_PHDRSIZE,
	TimerOFF	= 0,
	TimerON		= 1,
	TimerDONE	= 2,
	TcptimerOFF	= 0,
	TcptimerON		= 1,
	TcptimerDONE	= 2,
	MAX_TIME 	= (1<<20),	/* Forever */
	TCP_ACK		= 200,		/* Timed ack sequence in ms */



@@ 73,12 73,12 @@ char *tcpstates[] =
	"Closing", 	"Last_ack", 	"Time_wait"
};

typedef struct Timer Timer;
struct Timer
typedef struct Tcptimer Tcptimer;
struct Tcptimer
{
	Timer	*next;
	Timer	*prev;
	Timer	*readynext;
	Tcptimer	*next;
	Tcptimer	*prev;
	Tcptimer	*readynext;
	int	state;
	int	start;
	int	count;


@@ 177,10 177,10 @@ struct Tcpctl
	int	backedoff;		/* ms we've backed off for rexmits */
	uchar	flags;			/* State flags */
	Reseq	*reseq;			/* Resequencing queue */
	Timer	timer;			/* Activity timer */
	Timer	acktimer;		/* Acknowledge timer */
	Timer	rtt_timer;		/* Round trip timer */
	Timer	katimer;		/* keep alive timer */
	Tcptimer	timer;			/* Activity timer */
	Tcptimer	acktimer;		/* Acknowledge timer */
	Tcptimer	rtt_timer;		/* Round trip timer */
	Tcptimer	katimer;		/* keep alive timer */
	ulong	rttseq;			/* Round trip sequence */
	int	srtt;			/* Shortened round trip */
	int	mdev;			/* Mean deviation of round trip */


@@ 241,7 241,7 @@ static char *statnames[] =
typedef struct Tcppriv Tcppriv;
struct Tcppriv
{
	Timer 	*timers;		/* List of active timers */
	Tcptimer 	*timers;		/* List of active timers */
	QLock 	tl;			/* Protect timer list */
	Rendez	tcpr;			/* used by tcpackproc */



@@ 493,10 493,10 @@ tcpcreate(Conv *c)
}

static void
timerstate(Tcppriv *priv, Timer *t, int newstate)
timerstate(Tcppriv *priv, Tcptimer *t, int newstate)
{
	if(newstate != TimerON){
		if(t->state == TimerON){
	if(newstate != TcptimerON){
		if(t->state == TcptimerON){
			// unchain
			if(priv->timers == t){
				priv->timers = t->next;


@@ 510,7 510,7 @@ timerstate(Tcppriv *priv, Timer *t, int newstate)
			t->next = t->prev = nil;
		}
	} else {
		if(t->state != TimerON){
		if(t->state != TcptimerON){
			// chain
			if(t->prev != nil || t->next != nil)
				panic("timerstate2");


@@ 527,7 527,7 @@ timerstate(Tcppriv *priv, Timer *t, int newstate)
void
tcpackproc(void *a)
{
	Timer *t, *tp, *timeo;
	Tcptimer *t, *tp, *timeo;
	Proto *tcp;
	Tcppriv *priv;
	int loop;


@@ 545,10 545,10 @@ tcpackproc(void *a)
			if(loop++ > 10000)
				panic("tcpackproc1");
			tp = t->next;
 			if(t->state == TimerON) {
 			if(t->state == TcptimerON) {
				t->count--;
				if(t->count == 0) {
					timerstate(priv, t, TimerDONE);
					timerstate(priv, t, TcptimerDONE);
					t->readynext = timeo;
					timeo = t;
				}


@@ 560,7 560,7 @@ tcpackproc(void *a)
		for(t = timeo; t != nil; t = t->readynext) {
			if(loop++ > 10000)
				panic("tcpackproc2");
			if(t->state == TimerDONE && t->func != nil && !waserror()){
			if(t->state == TcptimerDONE && t->func != nil && !waserror()){
				(*t->func)(t->arg);
				poperror();
			}


@@ 569,25 569,25 @@ tcpackproc(void *a)
}

void
tcpgo(Tcppriv *priv, Timer *t)
tcpgo(Tcppriv *priv, Tcptimer *t)
{
	if(t == nil || t->start == 0)
		return;

	qlock(&priv->tl);
	t->count = t->start;
	timerstate(priv, t, TimerON);
	timerstate(priv, t, TcptimerON);
	qunlock(&priv->tl);
}

void
tcphalt(Tcppriv *priv, Timer *t)
tcphalt(Tcppriv *priv, Tcptimer *t)
{
	if(t == nil)
		return;

	qlock(&priv->tl);
	timerstate(priv, t, TimerOFF);
	timerstate(priv, t, TcptimerOFF);
	qunlock(&priv->tl);
}



@@ 1002,13 1002,13 @@ tcpincoming(Conv *s, Tcp *segp, uchar *src, uchar *dst)
	tcb = (Tcpctl*)new->ptcl;
	tcb->flags &= ~CLONE;
	tcb->timer.arg = new;
	tcb->timer.state = TimerOFF;
	tcb->timer.state = TcptimerOFF;
	tcb->acktimer.arg = new;
	tcb->acktimer.state = TimerOFF;
	tcb->acktimer.state = TcptimerOFF;
	tcb->katimer.arg = new;
	tcb->katimer.state = TimerOFF;
	tcb->katimer.state = TcptimerOFF;
	tcb->rtt_timer.arg = new;
	tcb->rtt_timer.state = TimerOFF;
	tcb->rtt_timer.state = TcptimerOFF;

	h = &tcb->protohdr;
	memset(h, 0, sizeof(*h));


@@ 1186,7 1186,7 @@ update(Conv *s, Tcp *seg)
	}

	/* Adjust the timers according to the round trip time */
	if(tcb->rtt_timer.state == TimerON && seq_ge(seg->ack, tcb->rttseq)) {
	if(tcb->rtt_timer.state == TcptimerON && seq_ge(seg->ack, tcb->rttseq)) {
		tcphalt(tpriv, &tcb->rtt_timer);
		if((tcb->flags&RETRAN) == 0) {
			tcb->backoff = 0;


@@ 1491,7 1491,7 @@ reset:
			}
		case Time_wait:
			tcb->flags |= FORCE;
			if(tcb->timer.state != TimerON)
			if(tcb->timer.state != TcptimerON)
				tcpgo(tpriv, &tcb->timer);
		}



@@ 1548,7 1548,7 @@ reset:
				 *  turn on the acktimer if there's something
				 *  to ack
				 */
				if(tcb->acktimer.state != TimerON)
				if(tcb->acktimer.state != TcptimerON)
					tcpgo(tpriv, &tcb->acktimer);

				break;


@@ 1792,14 1792,14 @@ tcpoutput(Conv *s)
		 * expect acknowledges
		 */
		if(ssize != 0){
			if(tcb->timer.state != TimerON)
			if(tcb->timer.state != TcptimerON)
				tcpgo(tpriv, &tcb->timer);

			/*  If round trip timer isn't running, start it.
			 *  measure the longest packet only in case the
			 *  transmission time dominates RTT
			 */
			if(tcb->rtt_timer.state != TimerON)
			if(tcb->rtt_timer.state != TcptimerON)
			if(ssize == tcb->mss) {
				tcpgo(tpriv, &tcb->rtt_timer);
				tcb->rttseq = tcb->snd.ptr;

M mtx/cycintr.c => mtx/cycintr.c +3 -3
@@ 6,18 6,18 @@
#include "io.h"

int
havecycintr(void)
havetimer(void)
{
	return 0;
}

void
cycintradd(Cycintr *)
timeradd(Timer *)
{
}

void
cycintrdel(Cycintr *)
timerdel(Timer *)
{
}


M mtx/dat.h => mtx/dat.h +4 -4
@@ 1,5 1,5 @@
typedef struct Conf	Conf;
typedef struct Cycintr		Cycintr;
typedef struct Timer		Timer;
typedef struct FPsave	FPsave;
typedef struct ISAConf	ISAConf;
typedef struct Label	Label;


@@ 195,12 195,12 @@ struct ISAConf {
/*
 * fasttick timer interrupts (Dummy for now)
 */
struct Cycintr
struct Timer
{
	vlong	when;			/* fastticks when f should be called */
	void	(*f)(Ureg*, Cycintr*);
	void	(*f)(Ureg*, Timer*);
	void	*a;
	Cycintr	*next;
	Timer	*next;
};

#define	MACHP(n)	((Mach *)((int)&mach0+n*BY2PG))

M mtx/fns.h => mtx/fns.h +3 -3
@@ 8,8 8,8 @@ void	clockinit(void);
void	clockintr(Ureg*);
void	clockintrsched(void);
#define coherence()	eieio()
void	cycintradd(Cycintr *);
void	cycintrdel(Cycintr *);
void	timeradd(Timer *);
void	timerdel(Timer *);
void	cpuidentify(void);
void	cpuidprint(void);
void	dcflush(void*, ulong);


@@ 36,7 36,7 @@ ulong	getpvr(void);
ulong	gettbl(void);
ulong	gettbu(void);
void	gotopc(ulong);
int	havecycintr(void);
int	havetimer(void);
void	hwintrinit(void);
void	i8250console(void);
void	i8259init(void);

M pc/archmp.c => pc/archmp.c +1 -0
@@ 102,4 102,5 @@ PCArch archmp = {
	0,					/* intrdisable */

	0,					/* clockenable */
	i8253read,				/* fastclock */
};

M pc/clock.c => pc/clock.c +7 -2
@@ 6,11 6,16 @@
#include "io.h"
#include "ureg.h"

/*
 *  this is called both by the mp's clock interrupt and
 *  by the clockintr0 for the i8253
 */
int nclockintr;
void
clockintr(Ureg* ureg, void*)
{
	// this needs to be here for synchronizing mp clocks
	// see pc/mp.c's squidboy()
nclockintr++;
	/* this has to get called every tick or the 8253 timer will overflow */
	fastticks(nil);

	if(m->flushmmu){

M pc/cycintr.c => pc/cycintr.c +27 -27
@@ 9,56 9,56 @@
static struct
{
	Lock;
	Cycintr	*ci;
}cycintrs;
	Timer	*ci;
}timers;

/*
 * called by clockintrsched()
 */
vlong
cycintrnext(void)
timernext(void)
{
	Cycintr *ci;
	Timer *ci;
	vlong when;

	ilock(&cycintrs);
	ilock(&timers);
	when = 0;
	ci = cycintrs.ci;
	ci = timers.ci;
	if(ci != nil)
		when = ci->when;
	iunlock(&cycintrs);
	iunlock(&timers);
	return when;
}

vlong
checkcycintr(Ureg *u, void*)
checktimer(Ureg *u, void*)
{
	Cycintr *ci;
	Timer *ci;
	vlong when;

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

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

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


@@ 67,7 67,7 @@ cycintradd(Cycintr *nci)
		last = &ci->next;
	}

	last = &cycintrs.ci;
	last = &timers.ci;
	while(ci = *last){
		if(ci->when > nci->when)
			break;


@@ 75,16 75,16 @@ cycintradd(Cycintr *nci)
	}
	nci->next = *last;
	*last = nci;
	iunlock(&cycintrs);
	iunlock(&timers);
}

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

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


@@ 92,5 92,5 @@ cycintrdel(Cycintr *dci)
		}
		last = &ci->next;
	}
	iunlock(&cycintrs);
	iunlock(&timers);
}

M pc/dat.h => pc/dat.h +6 -5
@@ 1,5 1,5 @@
typedef struct Conf	Conf;
typedef struct Cycintr	Cycintr;
typedef struct Timer	Timer;
typedef struct FPsave	FPsave;
typedef struct ISAConf	ISAConf;
typedef struct Label	Label;


@@ 176,7 176,6 @@ struct Mach
	int	syscall;
	int	load;
	int	intr;
	vlong	fastclock;		/* last sampled value */
	vlong	intrts;			/* time stamp of last interrupt */
	int	flushmmu;		/* make current proc flush it's mmu state */



@@ 191,6 190,8 @@ struct Mach
	int	cpuiddx;
	char	cpuidid[16];
	char*	cpuidtype;
	int	havetsc;
	vlong	lasttsc;		/* last sampled value */

	vlong	mtrrcap;
	vlong	mtrrdef;


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

/*

M pc/devarch.c => pc/devarch.c +27 -37
@@ 489,8 489,6 @@ nop(void)
}

void (*coherence)(void) = nop;
void cycletimerinit(void);
uvlong cycletimer(uvlong*);

PCArch* arch;
extern PCArch* knownarch[];


@@ 594,7 592,6 @@ static X86type x86winchip[] =
};


static uvlong fasthz;
static X86type *cputype;

void


@@ 611,6 608,15 @@ cpuidprint(void)
	print(buf);
}

/*
 *  figure out:
 *	- cpu type
 *	- whether or not we have a TSC (cycle counter)
 *	- whether or not is supports page size extensions
 *		(if so turn it on)
 *	- whether or not is supports machine check exceptions
 *		(if so turn it on)
 */
int
cpuidentify(void)
{


@@ 637,7 643,18 @@ cpuidentify(void)
		t++;
	}
	m->cpuidtype = t->name;
	i8253init(t->aalcycles, t->family >= 5);

	/*
	 *  if there is one, set tsc to a known value
	 */
	m->havetsc = t->family >= 5;
	if(m->havetsc)
		wrmsr(0x10, 0);

	/*
 	 *  use i8253 to guess our cpu speed
	 */
	guesscpuhz(t->aalcycles);

	/*
	 * If machine check exception or page size extensions are supported


@@ 703,17 720,12 @@ archinit(void)
			arch->serialpower = archgeneric.serialpower;
		if(arch->modempower == 0)
			arch->modempower = archgeneric.modempower;
	
		if(arch->intrinit == 0)
			arch->intrinit = archgeneric.intrinit;
		if(arch->intrenable == 0)
			arch->intrenable = archgeneric.intrenable;
	}

	/* pick the better timer */
	if(X86FAMILY(m->cpuidax) >= 5){
		cycletimerinit();
		arch->fastclock = cycletimer;
		if(arch->intrenable == 0)
			arch->intrenable = archgeneric.intrenable;
	}

	/*


@@ 728,40 740,18 @@ archinit(void)
	addarchfile("cputype", 0444, cputyperead, nil);
}

void
cycletimerinit(void)
{
	wrmsr(0x10, 0);
	fasthz = m->cpuhz;
}

/*
 *  return the most precise clock we have
 *  call either the pcmcia or pccard device setup
 */
uvlong
cycletimer(uvlong *hz)
{
	uvlong tsc;

	if(hz != nil)
		*hz = fasthz;
	rdtsc((vlong*)&tsc);
	m->fastclock = tsc;
	return tsc;
}

vlong
fastticks(uvlong *hz)
{
	return (*arch->fastclock)(hz);
}

int
pcmspecial(char *idstr, ISAConf *isa)
{
	return (_pcmspecial  != nil)? _pcmspecial(idstr, isa): -1;
}

/*
 *  call either the pcmcia or pccard device teardown
 */
void
pcmspecialclose(int a)
{

M pc/etherelnk3.c => pc/etherelnk3.c +3 -3
@@ 181,7 181,7 @@ enum {						/* Window 1 - operating set */
	Fifo			= 0x0000,
	RxError			= 0x0004,	/* 3C59[0257] only */
	RxStatus		= 0x0008,
	Timer			= 0x000A,
	Timerx			= 0x000A,
	TxStatus		= 0x000B,
	TxFree			= 0x000C,
						/* RxError bits */


@@ 999,7 999,7 @@ interrupt(Ureg*, void* arg)
	if(ctlr->busmaster == 2)
		ctlr->timer[0] += inb(port+Timer905) & 0xFF;
	else
		ctlr->timer[0] += inb(port+Timer) & 0xFF;
		ctlr->timer[0] += inb(port+Timerx) & 0xFF;

	do{
		if(status & hostError){


@@ 1167,7 1167,7 @@ interrupt(Ureg*, void* arg)
	if(ctlr->busmaster == 2)
		ctlr->timer[1] += inb(port+Timer905) & 0xFF;
	else
		ctlr->timer[1] += inb(port+Timer) & 0xFF;
		ctlr->timer[1] += inb(port+Timerx) & 0xFF;

	COMMAND(port, SelectRegisterWindow, w);
	iunlock(&ctlr->wlock);

M pc/fns.h => pc/fns.h +8 -6
@@ 6,7 6,7 @@ Dirtab*	addarchfile(char*, int, long(*)(Chan*,void*,long,vlong), long(*)(Chan*,v
void	apicclkenable(void);
void	archinit(void);
void	bootargs(ulong);
vlong	checkcycintr(Ureg*, void*);
vlong	checktimer(Ureg*, void*);
int	cistrcmp(char*, char*);
int	cistrncmp(char*, char*, int);
#define	clearmmucache()				/* x86 doesn't have one */


@@ 16,9 16,10 @@ void	(*coherence)(void);
void	cpuid(char*, int*, int*);
int	cpuidentify(void);
void	cpuidprint(void);
void	cycintradd(Cycintr*);
void	cycintrdel(Cycintr*);
vlong	cycintrnext(void);
void	timeradd(Timer*);
void	timerdel(Timer*);
void	timerset(vlong);
vlong	timernext(void);
void	delay(int);
int	dmacount(int);
int	dmadone(int);


@@ 37,14 38,15 @@ ulong	getcr2(void);
ulong	getcr3(void);
ulong	getcr4(void);
char*	getconf(char*);
void	guesscpuhz(int);
void	halt(void);
int	havecycintr(void);
int	havetimer(void);
int	i8042auxcmd(int);
void	i8042auxenable(void (*)(int, int));
void	i8042reset(void);
void	i8250console(void);
void*	i8250alloc(int, int, int);
void	i8253init(int, int);
void	i8253init(void);
void	i8253enable(void);
uvlong	i8253read(uvlong*);
void	i8259init(void);

M pc/i8253.c => pc/i8253.c +109 -65
@@ 21,6 21,12 @@ enum
	Load0l=	0x10,		/* load counter 0's lsb */
	Load0m=	0x20,		/* load counter 0's msb */
	Load0=	0x30,		/* load counter 0 with 2 bytes */

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

	Latch2=	0x80,		/* latch counter 2's value */
	Load2l=	0x90,		/* load counter 2's lsb */
	Load2m=	0xa0,		/* load counter 2's msb */


@@ 55,51 61,63 @@ enum
static struct
{
	Lock;
	int	havecyc;
	int	enabled;
	int	mode;
	vlong	when;		/* next fastticks a clock interrupt should occur */
	vlong	cycwhen;	/* next fastticks a cycintr happens; 0 == infinity */
	vlong	timerwhen;	/* next fastticks a cycintr happens; 0 == infinity */
	long	fastperiod;	/* fastticks/hz */
	long	fast2freq;	/* fastticks*FreqMul/Freq */

	Lock	lock1;		/* mutex for the following */
	ushort	last1;		/* last value of clock 1 */
	uvlong	ticks1;		/* cumulative ticks of counter 1 */
}i8253;

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

	if(initialised == 0){
		initialised = 1;
		i8253.havecyc = havecycleclock;
		ioalloc(T0cntr, 4, 0, "i8253");
		ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");
	ioalloc(T0cntr, 4, 0, "i8253");
	ioalloc(T2ctl, 1, 0, "i8253.cntr2ctl");

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

		/*
		 * 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;
		}
	/*
	 *  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;
	}
}

void
guesscpuhz(int aalcycles)
{
	int cpufreq, loops, incr, x, y;
	vlong a, b;

	/* find biggest loop that doesn't wrap */
	incr = 16000000/(aalcycles*HZ*2);


@@ 118,31 136,34 @@ i8253init(int aalcycles, int havecycleclock)
		 *  prefetch buffer.
		 *
		 */
		if(havecycleclock)
			rdtsc(&a);
		outb(Tmode, Latch0);
		if(m->havetsc)
			rdtsc(&a);
		x = inb(T0cntr);
		x |= inb(T0cntr)<<8;
		aamloop(loops);
		if(havecycleclock)
		outb(Tmode, Latch0);
		if(m->havetsc)
			rdtsc(&b);
		y = inb(T0cntr);
		y |= inb(T0cntr)<<8;
		x -= y;

	
		if(x < 0)
			x += Freq/HZ;

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

	/*
 	 *  figure out clock frequency and a loop multiplier for delay().
	 *  n.b. counter goes up by 2*Freq
	 */
	cpufreq = loops*((aalcycles*2*Freq)/x);
	m->loopconst = (cpufreq/1000)/aalcycles;	/* AAM+LOOP's for 1 ms */
	if(havecycleclock){

	if(m->havetsc){

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


@@ 165,7 186,7 @@ i8253init(int aalcycles, int havecycleclock)

/*
 * schedule the next interrupt
 * cycwhen is the next time for the cycle counter routines
 * timerwhen is the time of the next interrupt
 */
static void
clockintrsched0(vlong next)


@@ 173,7 194,7 @@ clockintrsched0(vlong next)
	vlong now;
	long set;

	i8253.cycwhen = next;
	i8253.timerwhen = next;
	if(i8253.mode == Square && next == 0)
		return;



@@ 201,9 222,9 @@ clockintrsched0(vlong next)
}

int
havecycintr(void)
havetimer(void)
{
	return i8253.havecyc && i8253.enabled;
	return i8253.enabled;
}

void


@@ 212,63 233,86 @@ clockintrsched(void)
	vlong next;

	ilock(&i8253);
	if(i8253.enabled && i8253.havecyc){
		next = cycintrnext();
		if(next != i8253.cycwhen)
	if(i8253.enabled){
		next = timernext();
		if(next != i8253.timerwhen)
			clockintrsched0(next);
	}
	iunlock(&i8253);
}

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

	if(!i8253.havecyc){
		clockintr(ureg, v);
		return;
	}
nclockintr0++;
	/* goes with syncing in squidboy */
	if(m->havetsc)
		rdtsc(&m->lasttsc);

	now = fastticks(nil);
	when = i8253.when;

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

	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));
	if(i8253.timerwhen || i8253.mode != Square)
		clockintrsched0(checktimer(ureg, v));
}

void
i8253enable(void)
{
	i8253.when = fastticks(nil);
	i8253.fastperiod = (m->cpuhz + HZ/2) / HZ;
	i8253.fast2freq = (vlong)m->cpuhz * FreqMul / Freq;
	uvlong hz;

	i8253.when = fastticks(&hz);
	i8253.fastperiod = (hz + HZ/2) / HZ;
	i8253.fast2freq = (hz * FreqMul) / Freq;
	i8253.enabled = 1;
	intrenable(IrqCLOCK, clockintr0, 0, BUSUNKNOWN, "clock");
}

/*
 *  return time elapsed since clock start in
 *  100 times hz
 *  return the total ticks of counter 1.  We shift by
 *  8 to give timesync more wriggle room for interpretation
 *  of the frequency
 */
uvlong
i8253read(uvlong *hz)
{
	ushort y, x;
	uvlong ticks;

	if(hz)
		*hz = HZ*100;
	return m->ticks*100;
		*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);
}

M pc/main.c => pc/main.c +1 -0
@@ 80,6 80,7 @@ main(void)

	print("\nPlan 9\n");

	i8253init();
	cpuidentify();
	screeninit();
	meminit();

M pc/mp.c => pc/mp.c +11 -10
@@ 403,16 403,17 @@ squidboy(Apic* apic)
	mprdthi |= (1<<apic->apicno)<<24;
	unlock(&mprdthilock);

	/*
	 * Restrain your octopus! Don't let it go out on the sea!
	 */
	ilock(&mpclocksynclock);
	x = MACHP(0)->ticks;
	while(MACHP(0)->ticks == x)
		;
	wrmsr(0x10, MACHP(0)->fastclock); /* synchronize fast counters */
	iunlock(&mpclocksynclock);

	if(m->havetsc){
		/*
		 * Restrain your octopus! Don't let it go out on the sea!
		 */
		ilock(&mpclocksynclock);
		x = MACHP(0)->ticks;
		while(MACHP(0)->ticks == x)
			;
		wrmsr(0x10, MACHP(0)->lasttsc); /* synchronize fast counters */
		iunlock(&mpclocksynclock);
	}
	lapicinit(apic);
	lapiconline();


M pc/vgavmware.c => pc/vgavmware.c +6 -18
@@ 157,7 157,6 @@ vmwarelinear(VGAscr* scr, int* size, int* align)
	oapsize = scr->apsize;
	wasupamem = scr->isupamem;

iprint("osize %d oaperture %.8lux oapsize %d wasupamem %d\n", osize, oaperture, oapsize, wasupamem);
	p = pcimatch(nil, PCIVMWARE, 0);
	if(p == nil)
		error("no vmware card found");


@@ 189,12 188,8 @@ iprint("osize %d oaperture %.8lux oapsize %d wasupamem %d\n", osize, oaperture, 
		if(wasupamem && upamalloc(oaperture, oapsize, 0))
			scr->isupamem = 1;
	}else
{
memset((void*)KADDR(aperture), 0x7F, 1048576);
		scr->isupamem = 1;
}

iprint("aperture %lux size %lux\n", aperture, *size);
	if(oaperture && aperture != oaperture)
		print("warning (BUG): redefinition of aperture does not change vmwarescreen segment\n");
	addvgaseg("vmwarescreen", aperture, osize);


@@ 306,14 301,13 @@ vmwarescroll(VGAscr*, Rectangle r, Rectangle sr)
{
	if(vm->mmio == nil)
		return 0;
	vmfifowr(vm, Xrectropcopy);
	vmfifowr(vm, r.max.x);
	vmfifowr(vm, r.max.y);
	vmfifowr(vm, Xrectcopy);
	vmfifowr(vm, sr.min.x);
	vmfifowr(vm, sr.min.y);
	vmfifowr(vm, r.min.x);
	vmfifowr(vm, r.min.y);
	vmfifowr(vm, sr.min.x - r.min.x);
	vmfifowr(vm, sr.min.y - r.min.y);
	vmfifowr(vm, 3);	/* code for copy */
	vmfifowr(vm, Dx(r));
	vmfifowr(vm, Dy(r));
	vmwait(vm);
	return 1;
}


@@ 338,18 332,12 @@ vmwaredrawinit(VGAscr *scr)
{
	ulong mmiobase, mmiosize;

extern int iprintscreenputs;
	iprintscreenputs = 0;

	if(scr->mmio==nil){
		mmiobase = vmrd(vm, Rmemstart);
		if(mmiobase == 0){
			iprint("mmiobase 0\n");
		if(mmiobase == 0)
			return;
		}
		mmiosize = vmrd(vm, Rmemsize);
		scr->mmio = KADDR(upamalloc(mmiobase, mmiosize, 0));
iprint("mmio %p\n", scr->mmio);
		vm->mmio = scr->mmio;
		vm->mmiosize = mmiosize;
		if(scr->mmio == nil)

M port/devenv.c => port/devenv.c +23 -24
@@ 27,20 27,19 @@ envgen(Chan *c, char*, Dirtab*, int, int s, Dir *dp)
	}

	eg = envgrp(c);
	qlock(eg);

	rlock(eg);
	for(e = eg->entries; e && s; e = e->link)
		s--;

	if(e == 0) {
		qunlock(eg);
		runlock(eg);
		return -1;
	}

	/* make sure name string continues to exist after we release lock */
	kstrcpy(up->genbuf, e->name, sizeof up->genbuf);
	devdir(c, e->qid, up->genbuf, e->len, eve, 0666, dp);
	qunlock(eg);
	runlock(eg);
	return 1;
}



@@ 100,10 99,10 @@ envopen(Chan *c, int omode)
	else {
		if(omode != OREAD && !envwriteable(c))
			error(Eperm);
		qlock(eg);
		rlock(eg);
		e = envlookup(eg, nil, c->qid.path);
		if(e == 0) {
			qunlock(eg);
			runlock(eg);
			error(Enonexist);
		}
		if((omode & OTRUNC) && e->value) {


@@ 112,7 111,7 @@ envopen(Chan *c, int omode)
			e->value = 0;
			e->len = 0;
		}
		qunlock(eg);
		runlock(eg);
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;


@@ 132,9 131,9 @@ envcreate(Chan *c, char *name, int omode, ulong)
	omode = openmode(omode);
	eg = envgrp(c);

	qlock(eg);
	wlock(eg);
	if(waserror()) {
		qunlock(eg);
		wunlock(eg);
		nexterror();
	}



@@ 152,7 151,7 @@ envcreate(Chan *c, char *name, int omode, ulong)
	eg->entries = e;
	c->qid = e->qid;

	qunlock(eg);
	wunlock(eg);
	poperror();

	c->offset = 0;


@@ 170,7 169,7 @@ envremove(Chan *c)
		error(Eperm);

	eg = envgrp(c);
	qlock(eg);
	wlock(eg);
	l = &eg->entries;
	for(e = *l; e; e = e->link) {
		if(e->qid.path == c->qid.path)


@@ 179,13 178,13 @@ envremove(Chan *c)
	}

	if(e == 0) {
		qunlock(eg);
		wunlock(eg);
		error(Enonexist);
	}

	*l = e->link;
	eg->vers++;
	qunlock(eg);
	wunlock(eg);
	free(e->name);
	if(e->value)
		free(e->value);


@@ 215,10 214,10 @@ envread(Chan *c, void *a, long n, vlong off)
		return devdirread(c, a, n, 0, 0, envgen);

	eg = envgrp(c);
	qlock(eg);
	rlock(eg);
	e = envlookup(eg, nil, c->qid.path);
	if(e == 0) {
		qunlock(eg);
		rlock(eg);
		error(Enonexist);
	}



@@ 228,7 227,7 @@ envread(Chan *c, void *a, long n, vlong off)
		n = 0;
	else
		memmove(a, e->value+offset, n);
	qunlock(eg);
	runlock(eg);
	return n;
}



@@ 249,10 248,10 @@ envwrite(Chan *c, void *a, long n, vlong off)
		error(Etoobig);

	eg = envgrp(c);
	qlock(eg);
	wlock(eg);
	e = envlookup(eg, nil, c->qid.path);
	if(e == 0) {
		qunlock(eg);
		wunlock(eg);
		error(Enonexist);
	}



@@ 268,7 267,7 @@ envwrite(Chan *c, void *a, long n, vlong off)
	memmove(e->value+offset, a, n);
	e->qid.vers++;
	eg->vers++;
	qunlock(eg);
	wunlock(eg);
	return n;
}



@@ 299,7 298,7 @@ envcpy(Egrp *to, Egrp *from)
	Evalue **l, *ne, *e;

	l = &to->entries;
	qlock(from);
	rlock(from);
	for(e = from->entries; e; e = e->link) {
		ne = smalloc(sizeof(Evalue));
		ne->name = smalloc(strlen(e->name)+1);


@@ 313,7 312,7 @@ envcpy(Egrp *to, Egrp *from)
		*l = ne;
		l = &ne->link;
	}
	qunlock(from);
	runlock(from);
}

void


@@ 375,9 374,9 @@ getconfenv(void)
	char *p, *q;
	int n;

	qlock(eg);
	rlock(eg);
	if(waserror()) {
		qunlock(eg);
		runlock(eg);
		nexterror();
	}
	


@@ 400,6 399,6 @@ getconfenv(void)
	*q = 0;
	
	poperror();
	qunlock(eg);
	runlock(eg);
	return p;
}

M port/devloopback.c => port/devloopback.c +7 -7
@@ 35,7 35,7 @@ struct Link
	Queue	*oq;		/* output queue from other side & packets in the link */
	Queue	*iq;

	Cycintr	ci;		/* time to move packets from  next packet from oq */
	Timer	ci;		/* time to move packets from  next packet from oq */
};

struct Loop


@@ 105,7 105,7 @@ static vlong	gtime(uchar *p);
static void	closelink(Link *link, int dofree);
static void	pushlink(Link *link, vlong now);
static void	freelb(Loop *lb);
static void	linkintr(Ureg*, Cycintr *ci);
static void	linkintr(Ureg*, Timer *ci);

static void
loopbackinit(void)


@@ 129,7 129,7 @@ loopbackattach(char *spec)
	int chan;
	int dev;

	if(!havecycintr())
	if(!havetimer())
		error("can't time packets");

	dev = 0;


@@ 381,7 381,7 @@ closelink(Link *link, int dofree)
	link->tqtail = nil;
	link->tout = 0;
	link->tin = 0;
	cycintrdel(&link->ci);
	timerdel(&link->ci);
	iunlock(link);
	if(iq != nil){
		qclose(iq);


@@ 604,7 604,7 @@ looper(Loop *lb)
}

static void
linkintr(Ureg*, Cycintr *ci)
linkintr(Ureg*, Timer *ci)
{
	Link *link;



@@ 633,7 633,7 @@ pushlink(Link *link, vlong now)
		return;

	}
	cycintrdel(&link->ci);
	timerdel(&link->ci);

	/*
	 * put more blocks into the xmit queue


@@ 710,7 710,7 @@ pushlink(Link *link, vlong now)
	if(tin){
		if(tin < now)
			panic("loopback unfinished business");
		cycintradd(&link->ci);
		timeradd(&link->ci);
	}
	iunlock(link);
}

M port/devrealtime.c => port/devrealtime.c +3 -3
@@ 224,7 224,7 @@ devrtinit(void)
static Chan *
devrtattach(char *param)
{
	if(havecycintr() == 0)
	if(havetimer() == 0)
		error("no edf on multiprocessors");
	return devattach('R', param);
}


@@ 232,7 232,7 @@ devrtattach(char *param)
static Walkqid *
devrtwalk(Chan *c, Chan *nc, char **name, int nname)
{
	if (havecycintr() == 0)
	if (havetimer() == 0)
		error("no edf on multiprocessors");
	return devwalk(c, nc, name, nname, nil, 0, schedgen);
}


@@ 267,7 267,7 @@ devrtopen(Chan *c, int mode)
{
	Task *t;

	if (havecycintr() == 0)
	if (havetimer() == 0)
		error("no edf on multiprocessors");
	switch ((ulong)c->qid.path){
	case Qlog:

M port/edf.c => port/edf.c +13 -13
@@ 26,8 26,8 @@ char *edf_statename[] = {
	[EdfDeadline] =		"Deadline",
};

static Cycintr	cycdeadline;		/* Time of next deadline */
static Cycintr	cycrelease;		/* Time of next release */
static Timer	cycdeadline;		/* Time of next deadline */
static Timer	cycrelease;		/* Time of next release */

static int		initialized;
static uvlong	fasthz;	


@@ 70,8 70,8 @@ static void		edf_resched(Task *t);
static void		setdelta(void);
static void		testdelta(Task *thetask);
static char *	edf_testschedulability(Task *thetask);
static void		edfreleaseintr(Ureg *, Cycintr *cy);
static void		edfdeadlineintr(Ureg*, Cycintr*);
static void		edfreleaseintr(Ureg *, Timer *cy);
static void		edfdeadlineintr(Ureg*, Timer*);

void
edf_init(void)


@@ 214,11 214,11 @@ edfreleasetimer(void)
		return;
	DPRINT("edfreleasetimer clock\n");
	if (cycrelease.when)
		cycintrdel(&cycrelease);
		timerdel(&cycrelease);
	cycrelease.when = t->r;
	if (cycrelease.when <= now)
		cycrelease.when = now;
	cycintradd(&cycrelease);
	timeradd(&cycrelease);
	clockintrsched();
}



@@ 271,7 271,7 @@ edfdeadline(Proc *p, SEvent why)
		assert(0 && p == nil || nt == t);
	}
	if (cycdeadline.when){
		cycintrdel(&cycdeadline);
		timerdel(&cycdeadline);
		cycdeadline.when = 0;
		clockintrsched();
	}


@@ 406,13 406,13 @@ edf_expel(Task *t)
}

static void
edfreleaseintr(Ureg*, Cycintr*)
edfreleaseintr(Ureg*, Timer*)
{
	Task *t;

	DPRINT("%d edfreleaseintr\n", m->machno);

	cycintrdel(&cycrelease);
	timerdel(&cycrelease);
	cycrelease.when = 0;
	clockintrsched();



@@ 433,7 433,7 @@ edfreleaseintr(Ureg*, Cycintr*)
}

static void
edfdeadlineintr(Ureg*, Cycintr*)
edfdeadlineintr(Ureg*, Timer*)
{
	/* Task reached deadline */



@@ 442,7 442,7 @@ edfdeadlineintr(Ureg*, Cycintr*)

	DPRINT("%d edfdeadlineintr\n", m->machno);

	cycintrdel(&cycdeadline);
	timerdel(&cycdeadline);
	cycdeadline.when = 0;
	clockintrsched();



@@ 743,10 743,10 @@ edf_runproc(void)
			iunlock(&edflock);
			return p;
		}
		cycintrdel(&cycdeadline);
		timerdel(&cycdeadline);
	}
	cycdeadline.when = when;
	cycintradd(&cycdeadline);
	timeradd(&cycdeadline);
	clockintrsched();
	iunlock(&edflock);
	return p;

M port/portdat.h => port/portdat.h +1 -1
@@ 430,7 430,7 @@ struct Rgrp
struct Egrp
{
	Ref;
	QLock;
	RWlock;
	Evalue	*entries;
	ulong	path;	/* qid.path of next Evalue to be allocated */
	ulong	vers;	/* of Egrp */