xref: /plan9/sys/src/9/rb/clock.c (revision f43f8ee646e2cb29aea7fd7bb5fc7318a3f4921f)
1*f43f8ee6SDavid du Colombier /*
2*f43f8ee6SDavid du Colombier  * ar7161 clocks and timers
3*f43f8ee6SDavid du Colombier  */
4*f43f8ee6SDavid du Colombier #include	"u.h"
5*f43f8ee6SDavid du Colombier #include	"../port/lib.h"
6*f43f8ee6SDavid du Colombier #include	"mem.h"
7*f43f8ee6SDavid du Colombier #include	"dat.h"
8*f43f8ee6SDavid du Colombier #include	"fns.h"
9*f43f8ee6SDavid du Colombier #include	"io.h"
10*f43f8ee6SDavid du Colombier 
11*f43f8ee6SDavid du Colombier #include	"ureg.h"
12*f43f8ee6SDavid du Colombier 
13*f43f8ee6SDavid du Colombier enum {
14*f43f8ee6SDavid du Colombier 	Cyccntres	= 2, /* counter advances at ½ clock rate (mips 24k) */
15*f43f8ee6SDavid du Colombier 	Basetickfreq	= 680*Mhz / Cyccntres,	/* rb450g */
16*f43f8ee6SDavid du Colombier };
17*f43f8ee6SDavid du Colombier 
18*f43f8ee6SDavid du Colombier void (*kproftimer)(ulong);
19*f43f8ee6SDavid du Colombier 
20*f43f8ee6SDavid du Colombier void
silencewdog(void)21*f43f8ee6SDavid du Colombier silencewdog(void)
22*f43f8ee6SDavid du Colombier {
23*f43f8ee6SDavid du Colombier 	*Rstwdogtimer = Basetickfreq * 2 * 5;	/* pet the dog */
24*f43f8ee6SDavid du Colombier }
25*f43f8ee6SDavid du Colombier 
26*f43f8ee6SDavid du Colombier void
sicwdog(void)27*f43f8ee6SDavid du Colombier sicwdog(void)
28*f43f8ee6SDavid du Colombier {
29*f43f8ee6SDavid du Colombier 	*Rstwdogtimer = Basetickfreq * 2;
30*f43f8ee6SDavid du Colombier 	*Rstwdogctl = Wdogreset;		/* wake the dog */
31*f43f8ee6SDavid du Colombier }
32*f43f8ee6SDavid du Colombier 
33*f43f8ee6SDavid du Colombier void
wdogreset(void)34*f43f8ee6SDavid du Colombier wdogreset(void)
35*f43f8ee6SDavid du Colombier {
36*f43f8ee6SDavid du Colombier 	*Rstwdogtimer = Basetickfreq / 100;
37*f43f8ee6SDavid du Colombier 	*Rstwdogctl = Wdogreset;		/* wake the dog */
38*f43f8ee6SDavid du Colombier 	coherence();
39*f43f8ee6SDavid du Colombier 	*Rstwdogtimer = Basetickfreq / 10000;
40*f43f8ee6SDavid du Colombier 	coherence();
41*f43f8ee6SDavid du Colombier }
42*f43f8ee6SDavid du Colombier 
43*f43f8ee6SDavid du Colombier void
stopwdog(void)44*f43f8ee6SDavid du Colombier stopwdog(void)
45*f43f8ee6SDavid du Colombier {
46*f43f8ee6SDavid du Colombier 	*Rstwdogtimer = ~0;
47*f43f8ee6SDavid du Colombier 	*Rstwdogctl = Wdognoaction;		/* put the dog to sleep */
48*f43f8ee6SDavid du Colombier }
49*f43f8ee6SDavid du Colombier 
50*f43f8ee6SDavid du Colombier void
clockshutdown(void)51*f43f8ee6SDavid du Colombier clockshutdown(void)
52*f43f8ee6SDavid du Colombier {
53*f43f8ee6SDavid du Colombier 	stopwdog();
54*f43f8ee6SDavid du Colombier }
55*f43f8ee6SDavid du Colombier 
56*f43f8ee6SDavid du Colombier /*
57*f43f8ee6SDavid du Colombier  *  delay for l milliseconds more or less.
58*f43f8ee6SDavid du Colombier  */
59*f43f8ee6SDavid du Colombier void
delay(int l)60*f43f8ee6SDavid du Colombier delay(int l)
61*f43f8ee6SDavid du Colombier {
62*f43f8ee6SDavid du Colombier 	while(l-- > 0)
63*f43f8ee6SDavid du Colombier 		microdelay(1000);
64*f43f8ee6SDavid du Colombier }
65*f43f8ee6SDavid du Colombier 
66*f43f8ee6SDavid du Colombier /*
67*f43f8ee6SDavid du Colombier  *  microseconds delay
68*f43f8ee6SDavid du Colombier  */
69*f43f8ee6SDavid du Colombier void
microdelay(int l)70*f43f8ee6SDavid du Colombier microdelay(int l)
71*f43f8ee6SDavid du Colombier {
72*f43f8ee6SDavid du Colombier 	int s;
73*f43f8ee6SDavid du Colombier 	ulong x, cyc, cnt, speed;
74*f43f8ee6SDavid du Colombier 
75*f43f8ee6SDavid du Colombier 	speed = m->speed;
76*f43f8ee6SDavid du Colombier 	if (speed == 0)
77*f43f8ee6SDavid du Colombier 		speed = Basetickfreq / Mhz * Cyccntres;
78*f43f8ee6SDavid du Colombier 	cyc = (ulong)l * (speed / Cyccntres);
79*f43f8ee6SDavid du Colombier 	s = splhi();
80*f43f8ee6SDavid du Colombier 	cnt = rdcount();
81*f43f8ee6SDavid du Colombier 	x = cnt + cyc;
82*f43f8ee6SDavid du Colombier 	if (x < cnt || x >= ~0ul - Basetickfreq) {
83*f43f8ee6SDavid du Colombier 		/* counter will wrap between now and x, or x is too near ~0 */
84*f43f8ee6SDavid du Colombier 		wrcount(0);			/* somewhat drastic */
85*f43f8ee6SDavid du Colombier 		wrcompare(rdcompare() - cnt);	/* match new count */
86*f43f8ee6SDavid du Colombier 		x = cyc;
87*f43f8ee6SDavid du Colombier 	}
88*f43f8ee6SDavid du Colombier 	while(rdcount() < x)
89*f43f8ee6SDavid du Colombier 		;
90*f43f8ee6SDavid du Colombier 	splx(s);
91*f43f8ee6SDavid du Colombier 	silencewdog();
92*f43f8ee6SDavid du Colombier }
93*f43f8ee6SDavid du Colombier 
94*f43f8ee6SDavid du Colombier void
clock(Ureg * ureg)95*f43f8ee6SDavid du Colombier clock(Ureg *ureg)
96*f43f8ee6SDavid du Colombier {
97*f43f8ee6SDavid du Colombier 	wrcompare(rdcount()+m->maxperiod);	/* side-effect: dismiss intr */
98*f43f8ee6SDavid du Colombier 	silencewdog();
99*f43f8ee6SDavid du Colombier 	timerintr(ureg, 0);
100*f43f8ee6SDavid du Colombier }
101*f43f8ee6SDavid du Colombier 
102*f43f8ee6SDavid du Colombier enum {
103*f43f8ee6SDavid du Colombier 	Instrs		= 10*Mhz,
104*f43f8ee6SDavid du Colombier };
105*f43f8ee6SDavid du Colombier 
106*f43f8ee6SDavid du Colombier static long
issue1loop(void)107*f43f8ee6SDavid du Colombier issue1loop(void)
108*f43f8ee6SDavid du Colombier {
109*f43f8ee6SDavid du Colombier 	register int i;
110*f43f8ee6SDavid du Colombier 	long st;
111*f43f8ee6SDavid du Colombier 
112*f43f8ee6SDavid du Colombier 	i = Instrs;
113*f43f8ee6SDavid du Colombier 	st = perfticks();
114*f43f8ee6SDavid du Colombier 	do {
115*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
116*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
117*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
118*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
119*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
120*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
121*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
122*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
123*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i; --i; --i; --i; --i; --i;
124*f43f8ee6SDavid du Colombier 		--i; --i; --i; --i; --i;
125*f43f8ee6SDavid du Colombier 		/* omit 3 (--i) to account for conditional branch, nop & jump */
126*f43f8ee6SDavid du Colombier 		i -= 1+3;	 /* --i plus 3 omitted (--i) instructions */
127*f43f8ee6SDavid du Colombier 	} while(--i >= 0);
128*f43f8ee6SDavid du Colombier 	return perfticks() - st;
129*f43f8ee6SDavid du Colombier }
130*f43f8ee6SDavid du Colombier 
131*f43f8ee6SDavid du Colombier /* estimate instructions/s. */
132*f43f8ee6SDavid du Colombier static int
guessmips(long (* loop)(void),char *)133*f43f8ee6SDavid du Colombier guessmips(long (*loop)(void), char *)
134*f43f8ee6SDavid du Colombier {
135*f43f8ee6SDavid du Colombier 	int s;
136*f43f8ee6SDavid du Colombier 	long cyc;
137*f43f8ee6SDavid du Colombier 
138*f43f8ee6SDavid du Colombier 	do {
139*f43f8ee6SDavid du Colombier 		s = splhi();
140*f43f8ee6SDavid du Colombier 		cyc = loop();
141*f43f8ee6SDavid du Colombier 		splx(s);
142*f43f8ee6SDavid du Colombier 		if (cyc < 0)
143*f43f8ee6SDavid du Colombier 			iprint("again...");
144*f43f8ee6SDavid du Colombier 	} while (cyc < 0);
145*f43f8ee6SDavid du Colombier 	/*
146*f43f8ee6SDavid du Colombier 	 * Instrs instructions took cyc cycles @ Basetickfreq Hz.
147*f43f8ee6SDavid du Colombier 	 * round the result.
148*f43f8ee6SDavid du Colombier 	 */
149*f43f8ee6SDavid du Colombier 	return (((vlong)Basetickfreq * Instrs) / cyc + Mhz/2) / Mhz;
150*f43f8ee6SDavid du Colombier }
151*f43f8ee6SDavid du Colombier 
152*f43f8ee6SDavid du Colombier void
clockinit(void)153*f43f8ee6SDavid du Colombier clockinit(void)
154*f43f8ee6SDavid du Colombier {
155*f43f8ee6SDavid du Colombier 	int mips;
156*f43f8ee6SDavid du Colombier 
157*f43f8ee6SDavid du Colombier 	silencewdog();
158*f43f8ee6SDavid du Colombier 
159*f43f8ee6SDavid du Colombier 	/*
160*f43f8ee6SDavid du Colombier 	 * calibrate fastclock
161*f43f8ee6SDavid du Colombier 	 */
162*f43f8ee6SDavid du Colombier 	mips = guessmips(issue1loop, "single");
163*f43f8ee6SDavid du Colombier 
164*f43f8ee6SDavid du Colombier 	/*
165*f43f8ee6SDavid du Colombier 	 * m->delayloop should be the number of delay loop iterations
166*f43f8ee6SDavid du Colombier 	 * needed to consume 1 ms, assuming 2 instr'ns in the delay loop.
167*f43f8ee6SDavid du Colombier 	 */
168*f43f8ee6SDavid du Colombier 	m->delayloop = mips*Mhz / (1000 * 2);
169*f43f8ee6SDavid du Colombier 	if(m->delayloop == 0)
170*f43f8ee6SDavid du Colombier 		m->delayloop = 1;
171*f43f8ee6SDavid du Colombier 
172*f43f8ee6SDavid du Colombier 	m->speed = mips;
173*f43f8ee6SDavid du Colombier 	m->hz = m->speed*Mhz;
174*f43f8ee6SDavid du Colombier 
175*f43f8ee6SDavid du Colombier 	m->maxperiod = Basetickfreq / HZ;
176*f43f8ee6SDavid du Colombier 	m->minperiod = Basetickfreq / (100*HZ);
177*f43f8ee6SDavid du Colombier 	wrcompare(rdcount()+m->maxperiod);
178*f43f8ee6SDavid du Colombier 
179*f43f8ee6SDavid du Colombier 	/*
180*f43f8ee6SDavid du Colombier 	 *  desynchronize the processor clocks so that they all don't
181*f43f8ee6SDavid du Colombier 	 *  try to resched at the same time.
182*f43f8ee6SDavid du Colombier 	 */
183*f43f8ee6SDavid du Colombier 	delay(m->machno*2);
184*f43f8ee6SDavid du Colombier 
185*f43f8ee6SDavid du Colombier 	syncclock();
186*f43f8ee6SDavid du Colombier 	intron(INTR7);
187*f43f8ee6SDavid du Colombier }
188*f43f8ee6SDavid du Colombier 
189*f43f8ee6SDavid du Colombier /*
190*f43f8ee6SDavid du Colombier  * Tval is supposed to be in fastticks units.
191*f43f8ee6SDavid du Colombier  * One fasttick unit is 1/Basetickfreq seconds.
192*f43f8ee6SDavid du Colombier  */
193*f43f8ee6SDavid du Colombier void
timerset(Tval next)194*f43f8ee6SDavid du Colombier timerset(Tval next)
195*f43f8ee6SDavid du Colombier {
196*f43f8ee6SDavid du Colombier 	int x;
197*f43f8ee6SDavid du Colombier 	long period;
198*f43f8ee6SDavid du Colombier 
199*f43f8ee6SDavid du Colombier 	if(next == 0)
200*f43f8ee6SDavid du Colombier 		return;
201*f43f8ee6SDavid du Colombier 	x = splhi();			/* don't let us get scheduled */
202*f43f8ee6SDavid du Colombier 	period = next - fastticks(nil);
203*f43f8ee6SDavid du Colombier 	if(period > m->maxperiod - m->minperiod)
204*f43f8ee6SDavid du Colombier 		period = m->maxperiod;
205*f43f8ee6SDavid du Colombier 	else if(period < m->minperiod)
206*f43f8ee6SDavid du Colombier 		period = m->minperiod;
207*f43f8ee6SDavid du Colombier 	wrcompare(rdcount()+period);
208*f43f8ee6SDavid du Colombier 	silencewdog();
209*f43f8ee6SDavid du Colombier 	splx(x);
210*f43f8ee6SDavid du Colombier }
211*f43f8ee6SDavid du Colombier 
212*f43f8ee6SDavid du Colombier /*
213*f43f8ee6SDavid du Colombier  *  The rewriting of compare in this routine shouldn't be necessary.
214*f43f8ee6SDavid du Colombier  *  However, we lose clock interrupts if I don't, either a chip bug
215*f43f8ee6SDavid du Colombier  *  or one of ours -- presotto
216*f43f8ee6SDavid du Colombier  */
217*f43f8ee6SDavid du Colombier uvlong
fastticks(uvlong * hz)218*f43f8ee6SDavid du Colombier fastticks(uvlong *hz)
219*f43f8ee6SDavid du Colombier {
220*f43f8ee6SDavid du Colombier 	int x;
221*f43f8ee6SDavid du Colombier 	ulong delta, count;
222*f43f8ee6SDavid du Colombier 
223*f43f8ee6SDavid du Colombier 	if(hz)
224*f43f8ee6SDavid du Colombier 		*hz = Basetickfreq;
225*f43f8ee6SDavid du Colombier 
226*f43f8ee6SDavid du Colombier 	/* avoid reentry on interrupt or trap, to prevent recursion */
227*f43f8ee6SDavid du Colombier 	x = splhi();
228*f43f8ee6SDavid du Colombier 	count = rdcount();
229*f43f8ee6SDavid du Colombier 	if(rdcompare() - count > m->maxperiod)
230*f43f8ee6SDavid du Colombier 		wrcompare(count+m->maxperiod);
231*f43f8ee6SDavid du Colombier 	silencewdog();
232*f43f8ee6SDavid du Colombier 
233*f43f8ee6SDavid du Colombier 	if (count < m->lastcount)		/* wrapped around? */
234*f43f8ee6SDavid du Colombier 		delta = count + ((1ull<<32) - m->lastcount);
235*f43f8ee6SDavid du Colombier 	else
236*f43f8ee6SDavid du Colombier 		delta = count - m->lastcount;
237*f43f8ee6SDavid du Colombier 	m->lastcount = count;
238*f43f8ee6SDavid du Colombier 	m->fastticks += delta;
239*f43f8ee6SDavid du Colombier 	splx(x);
240*f43f8ee6SDavid du Colombier 	return m->fastticks;
241*f43f8ee6SDavid du Colombier }
242*f43f8ee6SDavid du Colombier 
243*f43f8ee6SDavid du Colombier ulong
s(void)244*f43f8ee6SDavid du Colombier µs(void)
245*f43f8ee6SDavid du Colombier {
246*f43f8ee6SDavid du Colombier 	return fastticks2us(fastticks(nil));
247*f43f8ee6SDavid du Colombier }
248*f43f8ee6SDavid du Colombier 
249*f43f8ee6SDavid du Colombier /*
250*f43f8ee6SDavid du Colombier  *  performance measurement ticks.  must be low overhead.
251*f43f8ee6SDavid du Colombier  *  doesn't have to count over a second.
252*f43f8ee6SDavid du Colombier  */
253*f43f8ee6SDavid du Colombier ulong
perfticks(void)254*f43f8ee6SDavid du Colombier perfticks(void)
255*f43f8ee6SDavid du Colombier {
256*f43f8ee6SDavid du Colombier 	return rdcount();
257*f43f8ee6SDavid du Colombier }
258*f43f8ee6SDavid du Colombier 
259*f43f8ee6SDavid du Colombier long
lcycles(void)260*f43f8ee6SDavid du Colombier lcycles(void)
261*f43f8ee6SDavid du Colombier {
262*f43f8ee6SDavid du Colombier 	return perfticks();
263*f43f8ee6SDavid du Colombier }
264*f43f8ee6SDavid du Colombier 
265*f43f8ee6SDavid du Colombier /* should use vlong hw counters ideally; lcycles is inadequate */
266*f43f8ee6SDavid du Colombier void
cycles(uvlong * cycp)267*f43f8ee6SDavid du Colombier cycles(uvlong *cycp)
268*f43f8ee6SDavid du Colombier {
269*f43f8ee6SDavid du Colombier 	*cycp = fastticks(nil);
270*f43f8ee6SDavid du Colombier }
271*f43f8ee6SDavid du Colombier 
272*f43f8ee6SDavid du Colombier Lock mpsynclock;
273*f43f8ee6SDavid du Colombier 
274*f43f8ee6SDavid du Colombier /*
275*f43f8ee6SDavid du Colombier  *  synchronize all clocks with processor 0
276*f43f8ee6SDavid du Colombier  */
277*f43f8ee6SDavid du Colombier void
syncclock(void)278*f43f8ee6SDavid du Colombier syncclock(void)
279*f43f8ee6SDavid du Colombier {
280*f43f8ee6SDavid du Colombier 	uvlong x;
281*f43f8ee6SDavid du Colombier 
282*f43f8ee6SDavid du Colombier 	if(m->machno == 0){
283*f43f8ee6SDavid du Colombier 		m->lastcount = rdcount();
284*f43f8ee6SDavid du Colombier 		m->fastticks = 0;
285*f43f8ee6SDavid du Colombier 		m->ticks = 0;
286*f43f8ee6SDavid du Colombier 		wrcompare(rdcount()+m->maxperiod);
287*f43f8ee6SDavid du Colombier 	} else {
288*f43f8ee6SDavid du Colombier 		/* wait for processor 0's soft clock to change and then sync ours */
289*f43f8ee6SDavid du Colombier 		lock(&mpsynclock);
290*f43f8ee6SDavid du Colombier 		x = MACHP(0)->fastticks;
291*f43f8ee6SDavid du Colombier 		while(MACHP(0)->fastticks == x)
292*f43f8ee6SDavid du Colombier 			;
293*f43f8ee6SDavid du Colombier 		m->lastcount = rdcount();
294*f43f8ee6SDavid du Colombier 		m->fastticks = MACHP(0)->fastticks;
295*f43f8ee6SDavid du Colombier 		m->ticks = MACHP(0)->ticks;
296*f43f8ee6SDavid du Colombier 		wrcompare(rdcount()+m->maxperiod);
297*f43f8ee6SDavid du Colombier 		unlock(&mpsynclock);
298*f43f8ee6SDavid du Colombier 	}
299*f43f8ee6SDavid du Colombier }
300