308 lines · 5.7 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * ar7161 clocks and timers */#include	"u.h"#include	"../port/lib.h"#include	"mem.h"#include	"dat.h"#include	"fns.h"#include	"io.h" #include	"ureg.h" enum {	Cyccntres	= 2, /* counter advances at ½ clock rate (mips 24k) */	Basetickfreq	= 680*Mhz / Cyccntres,	/* rb450g */}; void (*kproftimer)(ulong); voidsilencewdog(void){	*Rstwdogtimer = Basetickfreq * 2 * 5;	/* pet the dog */} voidsicwdog(void){	*Rstwdogtimer = Basetickfreq * 2;	*Rstwdogctl = Wdogreset;		/* wake the dog */} voidwdogreset(void){	*Rstwdogtimer = Basetickfreq / 100;	*Rstwdogctl = Wdogreset;		/* wake the dog */	coherence();	*Rstwdogtimer = Basetickfreq / 10000;	coherence();} voidstopwdog(void){	*Rstwdogtimer = ~0;	*Rstwdogctl = Wdognoaction;		/* put the dog to sleep */} voidclockshutdown(void){	stopwdog();} /* *  delay for l milliseconds more or less. */voiddelay(int l){	while(l-- > 0)		microdelay(1000);} /* *  microseconds delay */voidmicrodelay(int l){	int s;	ulong x, cyc, cnt, speed; 	speed = m->speed;	if (speed == 0)		speed = Basetickfreq / Mhz * Cyccntres;	cyc = (ulong)l * (speed / Cyccntres);	s = splhi();	cnt = rdcount();	x = cnt + cyc;	if (x < cnt || x >= ~0ul - Basetickfreq) {		/* counter will wrap between now and x, or x is too near ~0 */		wrcount(0);			/* somewhat drastic */		wrcompare(rdcompare() - cnt);	/* match new count */		x = cyc;	}	while(rdcount() < x)		;	splx(s);	silencewdog();} voidclock(Ureg *ureg){	wrcompare(rdcount()+m->maxperiod);	/* side-effect: dismiss intr */	silencewdog();	timerintr(ureg, 0);} enum {	Instrs		= 10*Mhz,}; static longissue1loop(void){	register int i;	long st; 	i = Instrs;	st = perfticks();	do {		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;		--i; --i; --i; --i; --i;		/* omit 3 (--i) to account for conditional branch, nop & jump */		i -= 1+3;	 /* --i plus 3 omitted (--i) instructions */	} while(--i >= 0);	return perfticks() - st;} /* estimate instructions/s. */static intguessmips(long (*loop)(void), char *){	int s;	long cyc; 	do {		s = splhi();		cyc = loop();		splx(s);		if (cyc < 0)			iprint("again...");	} while (cyc < 0);	/*	 * Instrs instructions took cyc cycles @ Basetickfreq Hz.	 * round the result.	 */	return (((vlong)Basetickfreq * Instrs) / cyc + Mhz/2) / Mhz;} voidclockinit(void){	int mips; 	silencewdog(); 	/*	 * calibrate fastclock	 */	mips = guessmips(issue1loop, "single"); 	/*	 * m->delayloop should be the number of delay loop iterations	 * needed to consume 1 ms, assuming 2 instr'ns in the delay loop.	 */	m->delayloop = mips*Mhz / (1000 * 2);	if(m->delayloop == 0)		m->delayloop = 1; 	m->speed = mips;	m->hz = m->speed*Mhz; 	m->maxperiod = Basetickfreq / HZ;	m->minperiod = Basetickfreq / (100*HZ);	wrcompare(rdcount()+m->maxperiod); 	/*	 *  desynchronize the processor clocks so that they all don't	 *  try to resched at the same time.	 */	delay(m->machno*2); 	syncclock();	intron(INTR7);} /* * Tval is supposed to be in fastticks units. * One fasttick unit is 1/Basetickfreq seconds. */voidtimerset(Tval next){	int x;	long period; 	if(next == 0)		return;	x = splhi();			/* don't let us get scheduled */	period = next - fastticks(nil);	if(period > m->maxperiod - m->minperiod)		period = m->maxperiod;	else if(period < m->minperiod)		period = m->minperiod;	wrcompare(rdcount()+period);	silencewdog();	splx(x);} /* *  The rewriting of compare in this routine shouldn't be necessary. *  However, we lose clock interrupts if I don't, either a chip bug *  or one of ours -- presotto */uvlongfastticks(uvlong *hz){	int x;	ulong delta, count; 	if(hz)		*hz = Basetickfreq; 	/* avoid reentry on interrupt or trap, to prevent recursion */	x = splhi();	count = rdcount();	if(rdcompare() - count > m->maxperiod)		wrcompare(count+m->maxperiod);	silencewdog(); 	if (count < m->lastcount)		/* wrapped around? */		delta = count + ((1ull<<32) - m->lastcount);	else		delta = count - m->lastcount;	m->lastcount = count;	m->fastticks += delta;	splx(x);	return m->fastticks;} ulongµs(void){	return fastticks2us(fastticks(nil));} /* *  performance measurement ticks.  must be low overhead. *  doesn't have to count over a second. */ulongperfticks(void){	return rdcount();} longlcycles(void){	return perfticks();} /* should use vlong hw counters ideally; lcycles is inadequate */voidcycles(uvlong *cycp){	*cycp = fastticks(nil);} Lock mpsynclock; /* *  synchronize all clocks with processor 0 */voidsyncclock(void){	uvlong x; 	if(m->machno == 0){		m->lastcount = rdcount();		m->fastticks = 0;		m->ticks = 0;		wrcompare(rdcount()+m->maxperiod);	} else {		/* wait for processor 0's soft clock to change and then sync ours */		lock(&mpsynclock);		x = MACHP(0)->fastticks;		while(MACHP(0)->fastticks == x)			;		m->lastcount = rdcount();		m->fastticks = MACHP(0)->fastticks;		m->ticks = MACHP(0)->ticks;		wrcompare(rdcount()+m->maxperiod);		unlock(&mpsynclock);	}}