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