214 lines · 3.9 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. */ /* * kirkwood clocks * * timers count down to zero. */#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 */	Dogperiod	= 15 * CLOCKFREQ, /* at most 21 s.; must fit in ulong */	MaxPeriod	= Tcycles,	MinPeriod	= MaxPeriod / 100, 	/* timer ctl bits */	Tmr0enable	= 1<<0,	Tmr0reload	= 1<<1,	/* at 0 count, load timer0 from reload0 */	Tmr1enable	= 1<<2,	Tmr1reload	= 1<<3,	/* at 0 count, load timer1 from reload1 */	TmrWDenable	= 1<<4,	TmrWDreload	= 1<<5,}; typedef struct TimerReg TimerReg;struct TimerReg{	ulong	ctl;	ulong	pad[3];	ulong	reload0;	ulong	timer0;			/* cycles until zero */	ulong	reload1;	ulong	timer1;			/* cycles until zero */	ulong	reloadwd;	ulong	timerwd;}; static int ticks; /* for sanity checking; m->ticks doesn't always get updated */ static voidclockintr(Ureg *ureg, void *arg){	TimerReg *tmr = arg;	static int nesting; 	tmr->timerwd = Dogperiod;		/* reassure the watchdog */	ticks++;	coherence(); 	if (nesting == 0) {	/* if the clock interrupted itself, bail out */		++nesting;		timerintr(ureg, 0);		--nesting;	} 	intrclear(Irqbridge, IRQcputimer0);} /* stop clock interrupts and disable the watchdog timer */voidclockshutdown(void){	TimerReg *tmr = (TimerReg *)soc.clock; 	tmr->ctl = 0;	coherence();} voidclockinit(void){	int i, s;	CpucsReg *cpu = (CpucsReg *)soc.cpu;	TimerReg *tmr = (TimerReg *)soc.clock; 	clockshutdown(); 	/*	 * verify sanity of timer0	 */ 	intrenable(Irqbridge, IRQcputimer0, clockintr, tmr, "clock0");	s = spllo();			/* risky */	/* take any deferred clock (& other) interrupts here */	splx(s); 	/* adjust m->bootdelay, used by delay()? */	m->ticks = ticks = 0;	m->fastclock = 0; 	tmr->timer0 = 1;	tmr->ctl = Tmr0enable;		/* just once */	coherence(); 	s = spllo();			/* risky */	for (i = 0; i < 10 && ticks == 0; i++) {		delay(1);		coherence();	}	splx(s);	if (ticks == 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");	} 	/*	 * configure all timers	 */	clockshutdown();	tmr->reload0 = tmr->timer0 = Tcycles;	/* tick clock */	tmr->reload1 = tmr->timer1 = ~0;	/* cycle clock */	tmr->timerwd = Dogperiod;		/* watch dog timer */	coherence();	tmr->ctl = Tmr0enable | Tmr0reload | Tmr1enable | Tmr1reload |		TmrWDenable;	cpu->rstout |= RstoutWatchdog;	coherence();} voidtimerset(Tval next){	int offset;	TimerReg *tmr = (TimerReg *)soc.clock; 	offset = next - fastticks(nil);	if(offset < MinPeriod)		offset = MinPeriod;	else if(offset > MaxPeriod)		offset = MaxPeriod;	tmr->timer0 = offset;	coherence();} uvlongfastticks(uvlong *hz){	uvlong now;	int s; 	if(hz)		*hz = CLOCKFREQ;	s = splhi();	/* zero low ulong of fastclock */	now = (m->fastclock & ~(uvlong)~0ul) | perfticks();	if(now < m->fastclock)		/* low bits must have wrapped */		now += 1ll << 32;	m->fastclock = now;	splx(s);	return now;} ulongperfticks(void){	TimerReg *tmr = (TimerReg *)soc.clock; 	return ~tmr->timer1;} longlcycles(void){	return perfticks();} ulongµs(void){	return fastticks2us(fastticks(nil));} voidmicrodelay(int l){	int i; 	l *= m->delayloop;	l /= 1000;	if(l <= 0)		l = 1;	for(i = 0; i < l; i++)		;} voiddelay(int l){	ulong i, j; 	j = m->delayloop;	while(l-- > 0)		for(i=0; i < j; i++)			;}