Annotation of sys/arch/mips64/mips64/clock.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: clock.c,v 1.18 2007/04/29 17:35:27 kettenis Exp $ */
2:
3: /*
4: * Copyright (c) 2001-2004 Opsycon AB (www.opsycon.se / www.opsycon.com)
5: *
6: * Redistribution and use in source and binary forms, with or without
7: * modification, are permitted provided that the following conditions
8: * are met:
9: * 1. Redistributions of source code must retain the above copyright
10: * notice, this list of conditions and the following disclaimer.
11: * 2. Redistributions in binary form must reproduce the above copyright
12: * notice, this list of conditions and the following disclaimer in the
13: * documentation and/or other materials provided with the distribution.
14: *
15: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
16: * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17: * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19: * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: * SUCH DAMAGE.
26: *
27: */
28:
29: #include <sys/param.h>
30: #include <sys/kernel.h>
31: #include <sys/systm.h>
32: #include <sys/device.h>
33: #include <sys/evcount.h>
34: #include <sys/timetc.h>
35:
36: #include <machine/autoconf.h>
37: #include <machine/cpu.h>
38: #include <mips64/dev/clockvar.h>
39: #include <mips64/archtype.h>
40:
41: static struct evcount clk_count;
42: static int clk_irq = 5;
43:
44: /* Definition of the driver for autoconfig. */
45: int clockmatch(struct device *, void *, void *);
46: void clockattach(struct device *, struct device *, void *);
47: intrmask_t clock_int5_dummy(intrmask_t, struct trap_frame *);
48: intrmask_t clock_int5(intrmask_t, struct trap_frame *);
49: void clock_int5_init(struct clock_softc *);
50:
51: struct cfdriver clock_cd = {
52: NULL, "clock", DV_DULL, NULL, 0
53: };
54:
55: struct cfattach clock_ca = {
56: sizeof(struct clock_softc), clockmatch, clockattach
57: };
58:
59: int clock_started = 0;
60: u_int32_t cpu_counter_last;
61: u_int32_t cpu_counter_interval;
62: u_int32_t pendingticks;
63: u_int32_t ticktime;
64:
65: u_int cp0_get_timecount(struct timecounter *);
66:
67: struct timecounter cp0_timecounter = {
68: cp0_get_timecount, /* get_timecount */
69: 0, /* no poll_pps */
70: 0xffffffff, /* counter_mask */
71: 0, /* frequency */
72: "CP0", /* name */
73: 0 /* quality */
74: };
75:
76: #define SECMIN (60) /* seconds per minute */
77: #define SECHOUR (60*SECMIN) /* seconds per hour */
78:
79: #define YEARDAYS(year) (((((year) + 1900) % 4) == 0 && \
80: ((((year) + 1900) % 100) != 0 || \
81: (((year) + 1900) % 400) == 0)) ? 366 : 365)
82:
83: int
84: clockmatch(struct device *parent, void *cfdata, void *aux)
85: {
86: struct confargs *ca = aux;
87: struct cfdata *cf = cfdata;
88:
89: /* Make sure that we're looking for a clock. */
90: if (strcmp(ca->ca_name, clock_cd.cd_name) != 0)
91: return (0);
92:
93: if (cf->cf_unit >= 1)
94: return 0;
95: return 10; /* Try to get clock early */
96: }
97:
98: void
99: clockattach(struct device *parent, struct device *self, void *aux)
100: {
101: struct clock_softc *sc;
102:
103: md_clk_attach(parent, self, aux);
104: sc = (struct clock_softc *)self;
105:
106: switch (sys_config.system_type) {
107: case ALGOR_P4032:
108: case ALGOR_P5064:
109: case MOMENTUM_CP7000:
110: case MOMENTUM_CP7000G:
111: case MOMENTUM_JAGUAR:
112: case GALILEO_EV64240:
113: case SGI_INDY:
114: case SGI_O2:
115: case SGI_O200:
116: printf(" ticker on int5 using count register");
117: set_intr(INTPRI_CLOCK, CR_INT_5, clock_int5);
118: ticktime = sys_config.cpu[0].clock / 2000;
119: break;
120:
121: default:
122: panic("clockattach: it didn't get here. really.");
123: }
124:
125: printf("\n");
126: }
127:
128: /*
129: * Clock interrupt code for machines using the on cpu chip
130: * counter register. This register counts at half the pipeline
131: * frequency so the frequency must be known and the options
132: * register wired to allow it's use.
133: *
134: * The code is enabled by setting 'cpu_counter_interval'.
135: */
136: void
137: clock_int5_init(struct clock_softc *sc)
138: {
139: int s;
140:
141: s = splclock();
142: cpu_counter_interval = sys_config.cpu[0].clock / (hz * 2);
143: cpu_counter_last = cp0_get_count() + cpu_counter_interval * 4;
144: cp0_set_compare(cpu_counter_last);
145: splx(s);
146: }
147:
148: /*
149: * Dummy count register interrupt handler used on some targets.
150: * Just resets the compare register and acknowledge the interrupt.
151: */
152: intrmask_t
153: clock_int5_dummy(intrmask_t mask, struct trap_frame *tf)
154: {
155: cp0_set_compare(0); /* Shut up counter int's for a while */
156: return CR_INT_5; /* Clock is always on 5 */
157: }
158:
159: /*
160: * Interrupt handler for targets using the internal count register
161: * as interval clock. Normally the system is run with the clock
162: * interrupt always enabled. Masking is done here and if the clock
163: * can not be run the tick is just counted and handled later when
164: * the clock is unmasked again.
165: */
166: intrmask_t
167: clock_int5(intrmask_t mask, struct trap_frame *tf)
168: {
169: u_int32_t clkdiff;
170:
171: /*
172: * If clock is started count the tick, else just arm for a new.
173: */
174: if (clock_started && cpu_counter_interval != 0) {
175: clkdiff = cp0_get_count() - cpu_counter_last;
176: while (clkdiff >= cpu_counter_interval) {
177: cpu_counter_last += cpu_counter_interval;
178: clkdiff = cp0_get_count() - cpu_counter_last;
179: pendingticks++;
180: }
181: cpu_counter_last += cpu_counter_interval;
182: pendingticks++;
183: } else {
184: cpu_counter_last = cpu_counter_interval + cp0_get_count();
185: }
186:
187: cp0_set_compare(cpu_counter_last);
188: /* Make sure that next clock tick has not passed */
189: clkdiff = cp0_get_count() - cpu_counter_last;
190: if (clkdiff > 0) {
191: cpu_counter_last += cpu_counter_interval;
192: pendingticks++;
193: cp0_set_compare(cpu_counter_last);
194: }
195:
196: if ((tf->cpl & SPL_CLOCKMASK) == 0) {
197: while (pendingticks) {
198: clk_count.ec_count++;
199: hardclock(tf);
200: pendingticks--;
201: }
202: }
203:
204: return CR_INT_5; /* Clock is always on 5 */
205: }
206:
207: /*
208: * Wait "n" microseconds.
209: */
210: void
211: delay(int n)
212: {
213: int dly;
214: int p, c;
215:
216: p = cp0_get_count();
217: dly = (sys_config.cpu[0].clock / 1000000) * n / 2;
218: while (dly > 0) {
219: c = cp0_get_count();
220: dly -= c - p;
221: p = c;
222: }
223: }
224:
225: /*
226: * Wait "n" nanoseconds.
227: */
228: void
229: nanodelay(int n)
230: {
231: int dly;
232: int p, c;
233:
234: p = cp0_get_count();
235: dly = ((sys_config.cpu[0].clock * n) / 1000000000) / 2;
236: while (dly > 0) {
237: c = cp0_get_count();
238: dly -= c - p;
239: p = c;
240: }
241: }
242:
243: /*
244: * Mips machine independent clock routines.
245: */
246:
247: /*
248: * Start the real-time and statistics clocks. Leave stathz 0 since there
249: * are no other timers available.
250: */
251: void
252: cpu_initclocks()
253: {
254: struct clock_softc *sc = (struct clock_softc *)clock_cd.cd_devs[0];
255: struct tod_time ct;
256: u_int first_cp0, second_cp0, cycles_per_sec;
257: int first_sec;
258:
259: hz = sc->sc_clock.clk_hz;
260: stathz = sc->sc_clock.clk_stathz;
261: profhz = sc->sc_clock.clk_profhz;
262:
263: evcount_attach(&clk_count, "clock", (void *)&clk_irq, &evcount_intr);
264:
265: /* Start the clock. */
266: if (sc->sc_clock.clk_init != NULL)
267: (*sc->sc_clock.clk_init)(sc);
268:
269: /*
270: * Calibrate the cycle counter frequency.
271: */
272: if (sc->sc_clock.clk_get != NULL) {
273: (*sc->sc_clock.clk_get)(sc, 0, &ct);
274: first_sec = ct.sec;
275:
276: /* Let the clock tick one second. */
277: do {
278: first_cp0 = cp0_get_count();
279: (*sc->sc_clock.clk_get)(sc, 0, &ct);
280: } while (ct.sec == first_sec);
281: first_sec = ct.sec;
282: /* Let the clock tick one more second. */
283: do {
284: second_cp0 = cp0_get_count();
285: (*sc->sc_clock.clk_get)(sc, 0, &ct);
286: } while (ct.sec == first_sec);
287:
288: cycles_per_sec = second_cp0 - first_cp0;
289: sys_config.cpu[0].clock = cycles_per_sec * 2;
290: }
291:
292: tick = 1000000 / hz; /* number of micro-seconds between interrupts */
293: tickadj = 240000 / (60 * hz); /* can adjust 240ms in 60s */
294:
295: cp0_timecounter.tc_frequency = sys_config.cpu[0].clock / 2;
296: tc_init(&cp0_timecounter);
297:
298: clock_started++;
299: }
300:
301: /*
302: * We assume newhz is either stathz or profhz, and that neither will
303: * change after being set up above. Could recalculate intervals here
304: * but that would be a drag.
305: */
306: void
307: setstatclockrate(newhz)
308: int newhz;
309: {
310: }
311:
312: /*
313: * This code is defunct after 2099. Will Unix still be here then??
314: */
315: static short dayyr[12] = {
316: 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
317: };
318:
319: /*
320: * Initialize the time of day register, based on the time base which
321: * is, e.g. from a filesystem.
322: */
323: void
324: inittodr(time_t base)
325: {
326: struct timespec ts;
327: struct tod_time c;
328: struct clock_softc *sc = (struct clock_softc *)clock_cd.cd_devs[0];
329: int days, yr;
330:
331: ts.tv_nsec = 0;
332:
333: if (base < 15*SECYR) {
334: printf("WARNING: preposterous time in file system");
335: /* read the system clock anyway */
336: base = 17*SECYR + 186*SECDAY + SECDAY/2;
337: }
338:
339: /*
340: * Read RTC chip registers NOTE: Read routines are responsible
341: * for sanity checking clock. Dates after 19991231 should be
342: * returned as year >= 100.
343: */
344: if (sc->sc_clock.clk_get) {
345: (*sc->sc_clock.clk_get)(sc, base, &c);
346: } else {
347: printf("WARNING: No TOD clock, believing file system.\n");
348: goto bad;
349: }
350:
351: days = 0;
352: for (yr = 70; yr < c.year; yr++) {
353: days += YEARDAYS(yr);
354: }
355:
356: days += dayyr[c.mon - 1] + c.day - 1;
357: if (YEARDAYS(c.year) == 366 && c.mon > 2) {
358: days++;
359: }
360:
361: /* now have days since Jan 1, 1970; the rest is easy... */
362: ts.tv_sec = days * SECDAY + c.hour * 3600 + c.min * 60 + c.sec;
363: tc_setclock(&ts);
364: sc->sc_initted = 1;
365:
366: /*
367: * See if we gained/lost time.
368: */
369: if (base < ts.tv_sec - 5*SECYR) {
370: printf("WARNING: file system time much less than clock time\n");
371: } else if (base > ts.tv_sec + 5*SECYR) {
372: printf("WARNING: clock time much less than file system time\n");
373: printf("WARNING: using file system time\n");
374: } else {
375: return;
376: }
377:
378: bad:
379: ts.tv_sec = base;
380: tc_setclock(&ts);
381: sc->sc_initted = 1;
382: printf("WARNING: CHECK AND RESET THE DATE!\n");
383: }
384:
385: /*
386: * Reset the TOD clock. This is done when the system is halted or
387: * when the time is reset by the stime system call.
388: */
389: void
390: resettodr()
391: {
392: struct tod_time c;
393: struct clock_softc *sc = (struct clock_softc *)clock_cd.cd_devs[0];
394: register int t, t2;
395:
396: /*
397: * Don't reset clock if time has not been set!
398: */
399: if (!sc->sc_initted) {
400: return;
401: }
402:
403: /* compute the day of week. 1 is Sunday*/
404: t2 = time_second / SECDAY;
405: c.dow = (t2 + 5) % 7 + 1; /* 1/1/1970 was thursday */
406:
407: /* compute the year */
408: t2 = time_second / SECDAY;
409: c.year = 69;
410: while (t2 >= 0) { /* whittle off years */
411: t = t2;
412: c.year++;
413: t2 -= YEARDAYS(c.year);
414: }
415:
416: /* t = month + day; separate */
417: t2 = YEARDAYS(c.year);
418: for (c.mon = 1; c.mon < 12; c.mon++) {
419: if (t < dayyr[c.mon] + (t2 == 366 && c.mon > 1))
420: break;
421: }
422:
423: c.day = t - dayyr[c.mon - 1] + 1;
424: if (t2 == 366 && c.mon > 2) {
425: c.day--;
426: }
427:
428: t = time_second % SECDAY;
429: c.hour = t / 3600;
430: t %= 3600;
431: c.min = t / 60;
432: c.sec = t % 60;
433:
434: if (sc->sc_clock.clk_set) {
435: (*sc->sc_clock.clk_set)(sc, &c);
436: }
437: }
438:
439: u_int
440: cp0_get_timecount(struct timecounter *tc)
441: {
442: return (cp0_get_count());
443: }
CVSweb