Plan 9 from Bell Labs’s /usr/web/sources/plan9/sys/src/9/rb/clock.c

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


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

void
silencewdog(void)
{
	*Rstwdogtimer = Basetickfreq * 2 * 5;	/* pet the dog */
}

void
sicwdog(void)
{
	*Rstwdogtimer = Basetickfreq * 2;
	*Rstwdogctl = Wdogreset;		/* wake the dog */
}

void
wdogreset(void)
{
	*Rstwdogtimer = Basetickfreq / 100;
	*Rstwdogctl = Wdogreset;		/* wake the dog */
	coherence();
	*Rstwdogtimer = Basetickfreq / 10000;
	coherence();
}

void
stopwdog(void)
{
	*Rstwdogtimer = ~0;
	*Rstwdogctl = Wdognoaction;		/* put the dog to sleep */
}

void
clockshutdown(void)
{
	stopwdog();
}

/*
 *  delay for l milliseconds more or less.
 */
void
delay(int l)
{
	while(l-- > 0)
		microdelay(1000);
}

/*
 *  microseconds delay
 */
void
microdelay(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();
}

void
clock(Ureg *ureg)
{
	wrcompare(rdcount()+m->maxperiod);	/* side-effect: dismiss intr */
	silencewdog();
	timerintr(ureg, 0);
}

enum {
	Instrs		= 10*Mhz,
};

static long
issue1loop(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 int
guessmips(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;
}

void
clockinit(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.
 */
void
timerset(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
 */
uvlong
fastticks(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.
 */
ulong
perfticks(void)
{
	return rdcount();
}

long
lcycles(void)
{
	return perfticks();
}

/* should use vlong hw counters ideally; lcycles is inadequate */
void
cycles(uvlong *cycp)
{
	*cycp = fastticks(nil);
}

Lock mpsynclock;

/*
 *  synchronize all clocks with processor 0
 */
void
syncclock(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);
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].