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