Annotation of sys/arch/mvmeppc/dev/clock.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: clock.c,v 1.10 2004/12/24 22:50:30 miod Exp $ */
2: /* $NetBSD: clock.c,v 1.1 1996/09/30 16:34:40 ws Exp $ */
3:
4: /*
5: * Copyright (C) 1995, 1996 Wolfgang Solfrank.
6: * Copyright (C) 1995, 1996 TooLs GmbH.
7: * All rights reserved.
8: *
9: * Redistribution and use in source and binary forms, with or without
10: * modification, are permitted provided that the following conditions
11: * are met:
12: * 1. Redistributions of source code must retain the above copyright
13: * notice, this list of conditions and the following disclaimer.
14: * 2. Redistributions in binary form must reproduce the above copyright
15: * notice, this list of conditions and the following disclaimer in the
16: * documentation and/or other materials provided with the distribution.
17: * 3. All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by TooLs GmbH.
20: * 4. The name of TooLs GmbH may not be used to endorse or promote products
21: * derived from this software without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
24: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26: * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
29: * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
31: * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
32: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33: */
34:
35: #include <sys/param.h>
36: #include <sys/kernel.h>
37: #include <sys/systm.h>
38:
39: #include <machine/pio.h>
40: #include <machine/intr.h>
41: #include <machine/powerpc.h>
42:
43: #include "bugtty.h"
44:
45: void resettodr(void);
46: void decr_intr(struct clockframe *);
47: void calc_delayconst(void);
48:
49: /*
50: * Initially we assume a processor with a bus frequency of 12.5 MHz.
51: */
52: static u_long ticks_per_sec = 3125000;
53: static u_long ns_per_tick = 320;
54: static long ticks_per_intr;
55: static volatile u_long lasttb;
56:
57: /*
58: * BCD to decimal and decimal to BCD.
59: */
60: #define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf))
61: #define TOBCD(x) (((x) / 10 * 16) + ((x) % 10))
62:
63: #define SECDAY (24 * 60 * 60)
64: #define SECYR (SECDAY * 365)
65: #define LEAPYEAR(y) (((y) & 3) == 0)
66: #define YEAR0 1900
67:
68: tps_t *tps;
69: clock_read_t *clock_read;
70: clock_write_t *clock_write;
71: time_read_t *time_read;
72: time_write_t *time_write;
73:
74: static u_int32_t chiptotime(int, int, int, int, int, int);
75:
76: /* event tracking variables, when the next event of each time should occur */
77: u_int64_t nexttimerevent, prevtb, nextstatevent;
78:
79: /* vars for stats */
80: int statint;
81: u_int32_t statvar;
82: u_int32_t statmin;
83:
84: struct chiptime {
85: int sec;
86: int min;
87: int hour;
88: int wday;
89: int day;
90: int mon;
91: int year;
92: };
93:
94: static void timetochip(struct chiptime *c);
95:
96: /*
97: * For now we let the machine run with boot time, not changing the clock
98: * at inittodr at all.
99: *
100: * We might continue to do this due to setting up the real wall clock with
101: * a user level utility in the future.
102: */
103:
104: /* ARGSUSED */
105: void
106: inittodr(time_t base)
107: {
108: int sec, min, hour, day, mon, year;
109:
110: int badbase = 0, waszero = base == 0;
111:
112: if (base < 5 * SECYR) {
113: /*
114: * If base is 0, assume filesystem time is just unknown
115: * instead of preposterous. Don't bark.
116: */
117: if (base != 0)
118: printf("WARNING: preposterous time in file system\n");
119: /* not going to use it anyway, if the chip is readable */
120: base = 21*SECYR + 186*SECDAY + SECDAY/2;
121: badbase = 1;
122: }
123:
124: if (clock_read != NULL ) {
125: (*clock_read)( &sec, &min, &hour, &day, &mon, &year);
126: time.tv_sec = chiptotime(sec, min, hour, day, mon, year);
127: } else if (time_read != NULL) {
128: u_int32_t cursec;
129: (*time_read)(&cursec);
130: time.tv_sec = cursec;
131: } else {
132: /* force failure */
133: time.tv_sec = 0;
134: }
135:
136: if (time.tv_sec == 0) {
137: printf("WARNING: unable to get date/time");
138: /*
139: * Believe the time in the file system for lack of
140: * anything better, resetting the clock.
141: */
142: time.tv_sec = base;
143: if (!badbase)
144: resettodr();
145: } else {
146: int deltat;
147:
148: time.tv_sec += tz.tz_minuteswest * 60;
149: if (tz.tz_dsttime)
150: time.tv_sec -= 3600;
151:
152: deltat = time.tv_sec - base;
153:
154: if (deltat < 0)
155: deltat = -deltat;
156: if (waszero || deltat < 2 * SECDAY)
157: return;
158: printf("WARNING: clock %s %d days",
159: time.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
160:
161: if (time.tv_sec < base && deltat > 1000 * SECDAY) {
162: printf(", using FS time");
163: time.tv_sec = base;
164: }
165: }
166: printf(" -- CHECK AND RESET THE DATE!\n");
167: }
168:
169: /*
170: * This code is defunct after 2068.
171: * Will Unix still be here then??
172: */
173: const short dayyr[12] =
174: { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334};
175:
176: static u_int32_t
177: chiptotime(int sec, int min, int hour, int day, int mon, int year)
178: {
179: int days, yr;
180:
181: sec = FROMBCD(sec);
182: min = FROMBCD(min);
183: hour = FROMBCD(hour);
184: day = FROMBCD(day);
185: mon = FROMBCD(mon);
186: year = FROMBCD(year) + YEAR0;
187:
188: /* simple sanity checks */
189: if (year < 1970 || mon < 1 || mon > 12 || day < 1 || day > 31)
190: return (0);
191: days = 0;
192: for (yr = 1970; yr < year; yr++)
193: days += LEAPYEAR(yr) ? 366 : 365;
194: days += dayyr[mon - 1] + day - 1;
195: if (LEAPYEAR(yr) && mon > 2)
196: days++;
197: /* now have days since Jan 1, 1970; the rest is easy... */
198: return (days * SECDAY + hour * 3600 + min * 60 + sec);
199: }
200:
201: void
202: timetochip(struct chiptime *c)
203: {
204: int t, t2, t3, now = time.tv_sec;
205:
206: /* January 1 1970 was a Thursday (4 in unix wdays) */
207: /* compute the days since the epoch */
208: t2 = now / SECDAY;
209:
210: t3 = (t2 + 4) % 7; /* day of week */
211: c->wday = TOBCD(t3 + 1);
212:
213: /* compute the year */
214: t = 69;
215: while (t2 >= 0) { /* whittle off years */
216: t3 = t2;
217: t++;
218: t2 -= LEAPYEAR(t) ? 366 : 365;
219: }
220: c->year = t;
221:
222: /* t3 = month + day; separate */
223: t = LEAPYEAR(t);
224: for (t2 = 1; t2 < 12; t2++)
225: if (t3 < (dayyr[t2] + ((t && (t2 > 1)) ? 1:0)))
226: break;
227:
228: /* t2 is month */
229: c->mon = t2;
230: c->day = t3 - dayyr[t2 - 1] + 1;
231: if (t && t2 > 2)
232: c->day--;
233:
234: /* the rest is easy */
235: t = now % SECDAY;
236: c->hour = t / 3600;
237: t %= 3600;
238: c->min = t / 60;
239: c->sec = t % 60;
240:
241: c->sec = TOBCD(c->sec);
242: c->min = TOBCD(c->min);
243: c->hour = TOBCD(c->hour);
244: c->day = TOBCD(c->day);
245: c->mon = TOBCD(c->mon);
246: c->year = TOBCD((c->year - YEAR0) % 100);
247: }
248:
249:
250: /*
251: * Similar to the above
252: */
253: void
254: resettodr()
255: {
256: struct timeval curtime = time;
257: if (clock_write != NULL) {
258: struct chiptime c;
259: timetochip(&c);
260: (*clock_write)(c.sec, c.min, c.hour, c.day, c.mon, c.year);
261: } else if (time_write != NULL) {
262: curtime.tv_sec -= tz.tz_minuteswest * 60;
263: if (tz.tz_dsttime) {
264: curtime.tv_sec += 3600;
265: }
266: (*time_write)(curtime.tv_sec);
267: }
268: }
269:
270: volatile int statspending;
271:
272: void
273: decr_intr(struct clockframe *frame)
274: {
275: u_int64_t tb;
276: u_int64_t nextevent;
277: int nstats;
278: int s;
279:
280: /*
281: * Check whether we are initialized.
282: */
283: if (!ticks_per_intr)
284: return;
285:
286: /*
287: * Based on the actual time delay since the last decrementer reload,
288: * we arrange for earlier interrupt next time.
289: */
290:
291: tb = ppc_mftb();
292: while (nexttimerevent <= tb)
293: nexttimerevent += ticks_per_intr;
294:
295: prevtb = nexttimerevent - ticks_per_intr;
296:
297: for (nstats = 0; nextstatevent <= tb; nstats++) {
298: int r;
299: do {
300: r = random() & (statvar - 1);
301: } while (r == 0); /* random == 0 not allowed */
302: nextstatevent += statmin + r;
303: }
304:
305: if (nexttimerevent < nextstatevent)
306: nextevent = nexttimerevent;
307: else
308: nextevent = nextstatevent;
309:
310: /*
311: * Need to work about the near constant skew this introduces???
312: * reloading tb here could cause a missed tick.
313: */
314: ppc_mtdec(nextevent - tb);
315:
316: if (cpl & SPL_CLOCK) {
317: statspending += nstats;
318: } else {
319: nstats += statspending;
320: statspending = 0;
321:
322: s = splclock();
323:
324: /*
325: * Reenable interrupts
326: */
327: ppc_intr_enable(1);
328:
329: /*
330: * Do standard timer interrupt stuff.
331: * Do softclock stuff only on the last iteration.
332: */
333: frame->pri = s | SINT_CLOCK;
334: while (lasttb < prevtb - ticks_per_intr) {
335: /* sync lasttb with hardclock */
336: lasttb += ticks_per_intr;
337: hardclock(frame);
338: }
339:
340: frame->pri = s;
341: while (lasttb < prevtb) {
342: /* sync lasttb with hardclock */
343: lasttb += ticks_per_intr;
344: hardclock(frame);
345: #if NBUGTTY > 0
346: {
347: extern void bugtty_chkinput(void);
348: bugtty_chkinput();
349: }
350: #endif
351: }
352:
353: while (nstats-- > 0)
354: statclock(frame);
355:
356: splx(s);
357: ppc_intr_disable();
358:
359: /*
360: * If a tick has occurred while dealing with these,
361: * don't service it now, delay until the next tick.
362: */
363: }
364: }
365:
366: void
367: cpu_initclocks()
368: {
369: int intrstate;
370: int r;
371: int minint;
372: u_int64_t nextevent;
373:
374: intrstate = ppc_intr_disable();
375:
376: stathz = 100;
377: profhz = 1000; /* must be a multiple of stathz */
378:
379: /* init secondary clock to stathz */
380: statint = ticks_per_sec / stathz;
381: statvar = 0x40000000; /* really big power of two */
382: /* find largest 2^n which is nearly smaller than statint/2 */
383: minint = statint / 2 + 100;
384: while (statvar > minint)
385: statvar >>= 1;
386:
387: statmin = statint - (statvar >> 1);
388:
389: lasttb = ppc_mftb();
390: nexttimerevent = lasttb + ticks_per_intr;
391: do {
392: r = random() & (statvar - 1);
393: } while (r == 0); /* random == 0 not allowed */
394: nextstatevent = lasttb + statmin + r;
395:
396: if (nexttimerevent < nextstatevent)
397: nextevent = nexttimerevent;
398: else
399: nextevent = nextstatevent;
400:
401: ppc_mtdec(nextevent - lasttb);
402: ppc_intr_enable(intrstate);
403: }
404:
405: void
406: calc_delayconst(void)
407: {
408: int s;
409:
410: ticks_per_sec = (*tps)();
411: s = ppc_intr_disable();
412: ns_per_tick = 1000000000 / ticks_per_sec;
413: ticks_per_intr = ticks_per_sec / hz;
414: ppc_intr_enable(s);
415: }
416:
417: /*
418: * Fill in *tvp with current time with microsecond resolution.
419: */
420: void
421: microtime(struct timeval *tvp)
422: {
423: u_int64_t tb;
424: u_int32_t ticks;
425: int s;
426:
427: s = ppc_intr_disable();
428: tb = ppc_mftb();
429: ticks = ((tb - lasttb) * ns_per_tick) / 1000;
430: *tvp = time;
431: ppc_intr_enable(s);
432: tvp->tv_usec += ticks;
433: while (tvp->tv_usec >= 1000000) {
434: tvp->tv_usec -= 1000000;
435: tvp->tv_sec++;
436: }
437: }
438:
439: /*
440: * Wait for about n microseconds (us) (at least!).
441: */
442: void
443: delay(unsigned n)
444: {
445: u_int64_t tb;
446: u_int32_t tbh, tbl, scratch;
447:
448: tb = ppc_mftb();
449: tb += (n * 1000 + ns_per_tick - 1) / ns_per_tick;
450: tbh = tb >> 32;
451: tbl = (u_int32_t)tb;
452: asm ("1: mftbu %0; cmplw %0,%1; blt 1b; bgt 2f;"
453: " mftb %0; cmplw %0,%2; blt 1b; 2:"
454: :: "r"(scratch), "r"(tbh), "r"(tbl));
455: }
456:
457: void
458: setstatclockrate(int newhz)
459: {
460: int minint;
461: int intrstate;
462:
463: intrstate = ppc_intr_disable();
464:
465: statint = ticks_per_sec / newhz;
466: statvar = 0x40000000; /* really big power of two */
467: /* find largest 2^n which is nearly smaller than statint/2 */
468: minint = statint / 2 + 100;
469: while (statvar > minint)
470: statvar >>= 1;
471:
472: statmin = statint - (statvar >> 1);
473: ppc_intr_enable(intrstate);
474:
475: /*
476: * XXX this allows the next stat timer to occur then it switches
477: * to the new frequency. Rather than switching instantly.
478: */
479: }
CVSweb