Plan 9 from Bell Labs’s /usr/web/sources/patch/applied/kw-clock/clock.c

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


/*
 * kirkwood clock
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"
#include "io.h"

#include "ureg.h"

enum {
	Tcycles = CLOCKFREQ / HZ,		/* cycles per clock tick */
	MaxPeriod = Tcycles,
	MinPeriod = MaxPeriod / 100,
};

static void
clockintr(Ureg *ureg, void*)
{
	TIMERREG->timerwd = CLOCKFREQ;		/* reassure the watchdog */
	coherence();
	timerintr(ureg, 0);
	intrclear(Irqbridge, IRQcputimer0);
}

void
clockinit(void)
{
	int s;
	long cyc;
	TimerReg *tmr = TIMERREG;

	tmr->ctl = 0;
	coherence();
	intrenable(Irqbridge, IRQcputimer0, clockintr, nil, "clock");

	s = spllo();			/* risky */
	/* take any deferred clock (& other) interrupts here */
	splx(s);

	/* adjust m->bootdelay, used by delay()? */
	m->ticks = 0;
	m->fastclock = 0;

	tmr->timer0 = Tcycles;
	tmr->ctl = Tmr0enable;		/* just once */
	coherence();

	s = spllo();			/* risky */
	/* one iteration seems to take about 40 ns. */
	for (cyc = Tcycles; cyc > 0 && m->fastclock == 0; cyc--)
		;
	splx(s);

	if (m->fastclock == 0) {
		serialputc('?');
		if (tmr->timer0 == 0)
			panic("clock not interrupting");
		else if (tmr->timer0 == tmr->reload0)
			panic("clock not ticking");
		else
			panic("clock running very slowly");
	}

	tmr->ctl = 0;
	coherence();
	tmr->timer0  = Tcycles;
	tmr->timer1  = ~0;
	tmr->reload1 = ~0;
	tmr->timerwd = CLOCKFREQ;
	coherence();
	tmr->ctl = Tmr0enable | Tmr1enable | Tmr1periodic | TmrWDenable;
	CPUCSREG->rstout |= RstoutWatchdog;
	coherence();
}

void
timerset(Tval next)
{
	TimerReg *tmr = TIMERREG;
	int offset;

	offset = next - fastticks(nil);
	if(offset < MinPeriod)
		offset = MinPeriod;
	else if(offset > MaxPeriod)
		offset = MaxPeriod;
	tmr->timer0 = offset;
	coherence();
}

uvlong
fastticks(uvlong *hz)
{
	uvlong now;
	int s;

	if(hz)
		*hz = CLOCKFREQ;
	s = splhi();
	now = (m->fastclock&0xFFFFFFFF00000000LL) | ~TIMERREG->timer1;
	if(now < m->fastclock)
		now += 0x100000000LL;
	m->fastclock = now;
	splx(s);
	return now;
}

ulong
µs(void)
{
	return fastticks2us(fastticks(nil));
}

void
microdelay(int l)
{
	int i;

	l *= m->delayloop;
	l /= 1000;
	if(l <= 0)
		l = 1;
	for(i = 0; i < l; i++)
		;
}

void
delay(int l)
{
	ulong i, j;

	j = m->delayloop;
	while(l-- > 0)
		for(i=0; i < j; i++)
			;
}

ulong
perfticks(void)
{
	return ~TIMERREG->timer1;
}

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].