Annotation of sys/arch/sparc64/sparc64/clock.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: clock.c,v 1.33 2007/05/06 14:52:36 kettenis Exp $ */
2: /* $NetBSD: clock.c,v 1.41 2001/07/24 19:29:25 eeh Exp $ */
3:
4: /*
5: * Copyright (c) 1992, 1993
6: * The Regents of the University of California. All rights reserved.
7: * Copyright (c) 1994 Gordon W. Ross
8: * Copyright (c) 1993 Adam Glass
9: * Copyright (c) 1996 Paul Kranenburg
10: * Copyright (c) 1996
11: * The President and Fellows of Harvard College. All rights reserved.
12: *
13: * This software was developed by the Computer Systems Engineering group
14: * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
15: * contributed to Berkeley.
16: *
17: * All advertising materials mentioning features or use of this software
18: * must display the following acknowledgement:
19: * This product includes software developed by Harvard University.
20: * This product includes software developed by the University of
21: * California, Lawrence Berkeley Laboratory.
22: *
23: * Redistribution and use in source and binary forms, with or without
24: * modification, are permitted provided that the following conditions
25: * are met:
26: *
27: * 1. Redistributions of source code must retain the above copyright
28: * notice, this list of conditions and the following disclaimer.
29: * 2. Redistributions in binary form must reproduce the above copyright
30: * notice, this list of conditions and the following disclaimer in the
31: * documentation and/or other materials provided with the distribution.
32: * 3. All advertising materials mentioning features or use of this software
33: * must display the following acknowledgement:
34: * This product includes software developed by the University of
35: * California, Berkeley and its contributors.
36: * This product includes software developed by Paul Kranenburg.
37: * This product includes software developed by Harvard University.
38: * 4. Neither the name of the University nor the names of its contributors
39: * may be used to endorse or promote products derived from this software
40: * without specific prior written permission.
41: *
42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52: * SUCH DAMAGE.
53: *
54: * @(#)clock.c 8.1 (Berkeley) 6/11/93
55: *
56: */
57:
58: /*
59: * Clock driver. This is the id prom and eeprom driver as well
60: * and includes the timer register functions too.
61: */
62:
63: /* Define this for a 1/4s clock to ease debugging */
64: /* #define INTR_DEBUG */
65:
66: #include <sys/param.h>
67: #include <sys/kernel.h>
68: #include <sys/device.h>
69: #include <sys/proc.h>
70: #include <sys/resourcevar.h>
71: #include <sys/malloc.h>
72: #include <sys/systm.h>
73: #ifdef GPROF
74: #include <sys/gmon.h>
75: #endif
76: #include <sys/sched.h>
77: #include <sys/timetc.h>
78:
79: #include <uvm/uvm_extern.h>
80:
81: #include <machine/bus.h>
82: #include <machine/autoconf.h>
83: #include <machine/eeprom.h>
84: #include <machine/cpu.h>
85: #include <machine/idprom.h>
86:
87: #include <dev/clock_subr.h>
88: #include <dev/ic/mk48txxreg.h>
89:
90: #include <sparc64/sparc64/intreg.h>
91: #include <sparc64/sparc64/timerreg.h>
92: #include <sparc64/dev/iommureg.h>
93: #include <sparc64/dev/sbusreg.h>
94: #include <dev/sbus/sbusvar.h>
95: #include <sparc64/dev/ebusreg.h>
96: #include <sparc64/dev/ebusvar.h>
97: #include <sparc64/dev/fhcvar.h>
98:
99: extern u_int64_t cpu_clockrate;
100:
101: struct clock_wenable_info {
102: bus_space_tag_t cwi_bt;
103: bus_space_handle_t cwi_bh;
104: bus_size_t cwi_size;
105: };
106:
107: struct cfdriver clock_cd = {
108: NULL, "clock", DV_DULL
109: };
110:
111: u_int tick_get_timecount(struct timecounter *);
112:
113: struct timecounter tick_timecounter = {
114: tick_get_timecount, NULL, ~0u, 0, "tick", 0, NULL
115: };
116:
117: /*
118: * Statistics clock interval and variance, in usec. Variance must be a
119: * power of two. Since this gives us an even number, not an odd number,
120: * we discard one case and compensate. That is, a variance of 1024 would
121: * give us offsets in [0..1023]. Instead, we take offsets in [1..1023].
122: * This is symmetric about the point 512, or statvar/2, and thus averages
123: * to that value (assuming uniform random numbers).
124: */
125: /* XXX fix comment to match value */
126: int statvar = 8192;
127: int statmin; /* statclock interval - 1/2*variance */
128:
129: static long tick_increment;
130: int schedintr(void *);
131:
132: static struct intrhand level10 = { clockintr };
133: static struct intrhand level0 = { tickintr };
134: static struct intrhand level14 = { statintr };
135: static struct intrhand schedint = { schedintr };
136:
137: /*
138: * clock (eeprom) attaches at the sbus or the ebus (PCI)
139: */
140: static int clockmatch_sbus(struct device *, void *, void *);
141: static void clockattach_sbus(struct device *, struct device *, void *);
142: static int clockmatch_ebus(struct device *, void *, void *);
143: static void clockattach_ebus(struct device *, struct device *, void *);
144: static int clockmatch_fhc(struct device *, void *, void *);
145: static void clockattach_fhc(struct device *, struct device *, void *);
146: static void clockattach(int, bus_space_tag_t, bus_space_handle_t);
147:
148: struct cfattach clock_sbus_ca = {
149: sizeof(struct device), clockmatch_sbus, clockattach_sbus
150: };
151:
152: struct cfattach clock_ebus_ca = {
153: sizeof(struct device), clockmatch_ebus, clockattach_ebus
154: };
155:
156: struct cfattach clock_fhc_ca = {
157: sizeof(struct device), clockmatch_fhc, clockattach_fhc
158: };
159:
160: /* Global TOD clock handle & idprom pointer */
161: todr_chip_handle_t todr_handle = NULL;
162: static struct idprom *idprom;
163:
164: static int timermatch(struct device *, void *, void *);
165: static void timerattach(struct device *, struct device *, void *);
166:
167: struct timerreg_4u timerreg_4u; /* XXX - need more cleanup */
168:
169: struct cfattach timer_ca = {
170: sizeof(struct device), timermatch, timerattach
171: };
172:
173: struct cfdriver timer_cd = {
174: NULL, "timer", DV_DULL
175: };
176:
177: int clock_bus_wenable(struct todr_chip_handle *, int);
178: struct chiptime;
179: void myetheraddr(u_char *);
180: struct idprom *getidprom(void);
181: int chiptotime(int, int, int, int, int, int);
182: void timetochip(struct chiptime *);
183: void stopcounter(struct timer_4u *);
184:
185: int timerblurb = 10; /* Guess a value; used before clock is attached */
186:
187: /*
188: * The OPENPROM calls the clock the "eeprom", so we have to have our
189: * own special match function to call it the "clock".
190: */
191: static int
192: clockmatch_sbus(parent, cf, aux)
193: struct device *parent;
194: void *cf;
195: void *aux;
196: {
197: struct sbus_attach_args *sa = aux;
198:
199: return (strcmp("eeprom", sa->sa_name) == 0);
200: }
201:
202: static int
203: clockmatch_ebus(parent, cf, aux)
204: struct device *parent;
205: void *cf;
206: void *aux;
207: {
208: struct ebus_attach_args *ea = aux;
209:
210: return (strcmp("eeprom", ea->ea_name) == 0);
211: }
212:
213: static int
214: clockmatch_fhc(parent, cf, aux)
215: struct device *parent;
216: void *cf;
217: void *aux;
218: {
219: struct fhc_attach_args *fa = aux;
220:
221: return (strcmp("eeprom", fa->fa_name) == 0);
222: }
223:
224: /*
225: * Attach a clock (really `eeprom') to the sbus or ebus.
226: *
227: * We ignore any existing virtual address as we need to map
228: * this read-only and make it read-write only temporarily,
229: * whenever we read or write the clock chip. The clock also
230: * contains the ID ``PROM'', and I have already had the pleasure
231: * of reloading the cpu type, Ethernet address, etc, by hand from
232: * the console FORTH interpreter. I intend not to enjoy it again.
233: *
234: * the MK48T02 is 2K. the MK48T08 is 8K, and the MK48T59 is
235: * supposed to be identical to it.
236: *
237: * This is *UGLY*! We probably have multiple mappings. But I do
238: * know that this all fits inside an 8K page, so I'll just map in
239: * once.
240: *
241: * What we really need is some way to record the bus attach args
242: * so we can call *_bus_map() later with BUS_SPACE_MAP_READONLY
243: * or not to write enable/disable the device registers. This is
244: * a non-trivial operation.
245: */
246:
247: /* ARGSUSED */
248: static void
249: clockattach_sbus(parent, self, aux)
250: struct device *parent, *self;
251: void *aux;
252: {
253: struct sbus_attach_args *sa = aux;
254: bus_space_tag_t bt = sa->sa_bustag;
255: int sz;
256: static struct clock_wenable_info cwi;
257:
258: /* use sa->sa_regs[0].size? */
259: sz = 8192;
260:
261: if (sbus_bus_map(bt,
262: sa->sa_slot,
263: (sa->sa_offset & ~NBPG),
264: sz,
265: BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
266: 0, &cwi.cwi_bh) != 0) {
267: printf("%s: can't map register\n", self->dv_xname);
268: return;
269: }
270: clockattach(sa->sa_node, bt, cwi.cwi_bh);
271:
272: /* Save info for the clock wenable call. */
273: cwi.cwi_bt = bt;
274: cwi.cwi_size = sz;
275: todr_handle->bus_cookie = &cwi;
276: todr_handle->todr_setwen = clock_bus_wenable;
277: }
278:
279: /*
280: * Write en/dis-able clock registers. We coordinate so that several
281: * writers can run simultaneously.
282: * XXX There is still a race here. The page change and the "writers"
283: * change are not atomic.
284: */
285: int
286: clock_bus_wenable(handle, onoff)
287: struct todr_chip_handle *handle;
288: int onoff;
289: {
290: int s, err = 0;
291: int prot; /* nonzero => change prot */
292: volatile static int writers;
293: struct clock_wenable_info *cwi = handle->bus_cookie;
294:
295: s = splhigh();
296: if (onoff)
297: prot = writers++ == 0 ?
298: VM_PROT_READ | VM_PROT_WRITE | PMAP_WIRED : 0;
299: else
300: prot = --writers == 0 ?
301: VM_PROT_READ | PMAP_WIRED : 0;
302: splx(s);
303:
304: if (prot) {
305: err = bus_space_protect(cwi->cwi_bt, cwi->cwi_bh, cwi->cwi_size,
306: onoff ? 0 : BUS_SPACE_MAP_READONLY);
307: if (err)
308: printf("clock_wenable_info: WARNING -- cannot %s "
309: "page protection\n", onoff ? "disable" : "enable");
310: }
311: return (err);
312: }
313:
314: /* ARGSUSED */
315: static void
316: clockattach_ebus(parent, self, aux)
317: struct device *parent, *self;
318: void *aux;
319: {
320: struct ebus_attach_args *ea = aux;
321: bus_space_tag_t bt;
322: int sz;
323: static struct clock_wenable_info cwi;
324:
325: /* hard code to 8K? */
326: sz = ea->ea_regs[0].size;
327:
328: if (ebus_bus_map(ea->ea_iotag, 0,
329: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz, 0, 0, &cwi.cwi_bh) == 0) {
330: bt = ea->ea_iotag;
331: } else if (ebus_bus_map(ea->ea_memtag, 0,
332: EBUS_PADDR_FROM_REG(&ea->ea_regs[0]), sz,
333: BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY,
334: 0, &cwi.cwi_bh) == 0) {
335: bt = ea->ea_memtag;
336: } else {
337: printf("%s: can't map register\n", self->dv_xname);
338: return;
339: }
340:
341: clockattach(ea->ea_node, bt, cwi.cwi_bh);
342:
343: /* Save info for the clock wenable call. */
344: cwi.cwi_bt = bt;
345: cwi.cwi_size = sz;
346: todr_handle->bus_cookie = &cwi;
347: todr_handle->todr_setwen = (ea->ea_memtag == bt) ?
348: clock_bus_wenable : NULL;
349: }
350:
351: static void
352: clockattach_fhc(parent, self, aux)
353: struct device *parent, *self;
354: void *aux;
355: {
356: struct fhc_attach_args *fa = aux;
357: bus_space_tag_t bt = fa->fa_bustag;
358: int sz;
359: static struct clock_wenable_info cwi;
360:
361: /* use sa->sa_regs[0].size? */
362: sz = 8192;
363:
364: if (fhc_bus_map(bt, fa->fa_reg[0].fbr_slot,
365: (fa->fa_reg[0].fbr_offset & ~NBPG), fa->fa_reg[0].fbr_size,
366: BUS_SPACE_MAP_LINEAR | BUS_SPACE_MAP_READONLY, &cwi.cwi_bh) != 0) {
367: printf("%s: can't map register\n", self->dv_xname);
368: return;
369: }
370:
371: clockattach(fa->fa_node, bt, cwi.cwi_bh);
372:
373: /* Save info for the clock wenable call. */
374: cwi.cwi_bt = bt;
375: cwi.cwi_size = sz;
376: todr_handle->bus_cookie = &cwi;
377: todr_handle->todr_setwen = clock_bus_wenable;
378: }
379:
380: static void
381: clockattach(node, bt, bh)
382: int node;
383: bus_space_tag_t bt;
384: bus_space_handle_t bh;
385: {
386: char *model;
387: struct idprom *idp;
388: int h;
389:
390: model = getpropstring(node, "model");
391:
392: #ifdef DIAGNOSTIC
393: if (model == NULL)
394: panic("clockattach: no model property");
395: #endif
396:
397: /* Our TOD clock year 0 is 1968 */
398: if ((todr_handle = mk48txx_attach(bt, bh, model, 1968)) == NULL)
399: panic("Can't attach %s tod clock", model);
400:
401: #define IDPROM_OFFSET (8*1024 - 40) /* XXX - get nvram sz from driver */
402: if (idprom == NULL) {
403: idp = getidprom();
404: if (idp == NULL)
405: idp = (struct idprom *)(bus_space_vaddr(bt, bh) +
406: IDPROM_OFFSET);
407: idprom = idp;
408: } else
409: idp = idprom;
410: h = idp->id_machine << 24;
411: h |= idp->id_hostid[0] << 16;
412: h |= idp->id_hostid[1] << 8;
413: h |= idp->id_hostid[2];
414: hostid = h;
415: printf("\n");
416: }
417:
418: struct idprom *
419: getidprom()
420: {
421: struct idprom *idp = NULL;
422: int node, n;
423:
424: node = findroot();
425: if (getprop(node, "idprom", sizeof(*idp), &n, (void **)&idp) != 0)
426: return (NULL);
427: if (n != 1) {
428: free(idp, M_DEVBUF);
429: return (NULL);
430: }
431: return (idp);
432: }
433:
434: /*
435: * The sun4u OPENPROMs call the timer the "counter-timer", except for
436: * the lame UltraSPARC IIi PCI machines that don't have them.
437: */
438: static int
439: timermatch(parent, cf, aux)
440: struct device *parent;
441: void *cf;
442: void *aux;
443: {
444: struct mainbus_attach_args *ma = aux;
445:
446: if (!timerreg_4u.t_timer || !timerreg_4u.t_clrintr)
447: return (strcmp("counter-timer", ma->ma_name) == 0);
448: else
449: return (0);
450: }
451:
452: static void
453: timerattach(parent, self, aux)
454: struct device *parent, *self;
455: void *aux;
456: {
457: struct mainbus_attach_args *ma = aux;
458: u_int *va = ma->ma_address;
459:
460: /*
461: * What we should have are 3 sets of registers that reside on
462: * different parts of SYSIO or PSYCHO. We'll use the prom
463: * mappings cause we can't get rid of them and set up appropriate
464: * pointers on the timerreg_4u structure.
465: */
466: timerreg_4u.t_timer = (struct timer_4u *)(u_long)va[0];
467: timerreg_4u.t_clrintr = (int64_t *)(u_long)va[1];
468: timerreg_4u.t_mapintr = (int64_t *)(u_long)va[2];
469:
470: /* Install the appropriate interrupt vector here */
471: level10.ih_number = ma->ma_interrupts[0];
472: level10.ih_clr = (void *)&timerreg_4u.t_clrintr[0];
473: level10.ih_map = (void *)&timerreg_4u.t_mapintr[0];
474: strlcpy(level10.ih_name, "clock", sizeof(level10.ih_name));
475: intr_establish(10, &level10);
476:
477: level14.ih_number = ma->ma_interrupts[1];
478: level14.ih_clr = (void *)&timerreg_4u.t_clrintr[1];
479: level14.ih_map = (void *)&timerreg_4u.t_mapintr[1];
480: strlcpy(level14.ih_name, "prof", sizeof(level14.ih_name));
481: intr_establish(14, &level14);
482:
483: printf(" ivec 0x%x, 0x%x\n", INTVEC(level10.ih_number),
484: INTVEC(level14.ih_number));
485: }
486:
487: void
488: stopcounter(creg)
489: struct timer_4u *creg;
490: {
491: /* Stop the clock */
492: volatile int discard;
493: discard = creg->t_limit;
494: creg->t_limit = 0;
495: }
496:
497: /*
498: * XXX this belongs elsewhere
499: */
500: void
501: myetheraddr(cp)
502: u_char *cp;
503: {
504: struct idprom *idp;
505:
506: if ((idp = idprom) == NULL) {
507: int node, n;
508:
509: node = findroot();
510: if (getprop(node, "idprom", sizeof *idp, &n, (void **)&idp) ||
511: n != 1) {
512: printf("\nmyetheraddr: clock not setup yet, "
513: "and no idprom property in /\n");
514: return;
515: }
516: }
517:
518: cp[0] = idp->id_ether[0];
519: cp[1] = idp->id_ether[1];
520: cp[2] = idp->id_ether[2];
521: cp[3] = idp->id_ether[3];
522: cp[4] = idp->id_ether[4];
523: cp[5] = idp->id_ether[5];
524: if (idprom == NULL)
525: free(idp, M_DEVBUF);
526: }
527:
528: /*
529: * Set up the real-time and statistics clocks. Leave stathz 0 only if
530: * no alternative timer is available.
531: *
532: * The frequencies of these clocks must be an even number of microseconds.
533: */
534: void
535: cpu_initclocks()
536: {
537: int statint, minint;
538: #ifdef DEBUG
539: extern int intrdebug;
540: #endif
541:
542: #ifdef DEBUG
543: /* Set a 1s clock */
544: if (intrdebug) {
545: hz = 1;
546: tick = 1000000 / hz;
547: printf("intrdebug set: 1Hz clock\n");
548: }
549: #endif
550:
551: if (1000000 % hz) {
552: printf("cannot get %d Hz clock; using 100 Hz\n", hz);
553: hz = 100;
554: tick = 1000000 / hz;
555: }
556:
557: /* Make sure we have a sane cpu_clockrate -- we'll need it */
558: if (!cpu_clockrate)
559: /* Default to 200MHz clock XXXXX */
560: cpu_clockrate = 200000000;
561:
562: tick_timecounter.tc_frequency = cpu_clockrate;
563: tc_init(&tick_timecounter);
564:
565: /*
566: * Now handle machines w/o counter-timers.
567: */
568:
569: if (!timerreg_4u.t_timer || !timerreg_4u.t_clrintr) {
570: /* We don't have a counter-timer -- use %tick */
571: level0.ih_clr = 0;
572: /*
573: * Establish a level 10 interrupt handler
574: *
575: * We will have a conflict with the softint handler,
576: * so we set the ih_number to 1.
577: */
578: level0.ih_number = 1;
579: strlcpy(level0.ih_name, "clock", sizeof(level0.ih_name));
580: intr_establish(10, &level0);
581: /* We only have one timer so we have no statclock */
582: stathz = 0;
583:
584: /* set the next interrupt time */
585: tick_increment = cpu_clockrate / hz;
586: #ifdef DEBUG
587: printf("Using %%tick -- intr in %ld cycles...",
588: tick_increment);
589: #endif
590: next_tick(tick_increment);
591: #ifdef DEBUG
592: printf("done.\n");
593: #endif
594: return;
595: }
596:
597: if (stathz == 0)
598: stathz = hz;
599: if (1000000 % stathz) {
600: printf("cannot get %d Hz statclock; using 100 Hz\n", stathz);
601: stathz = 100;
602: }
603:
604: profhz = stathz; /* always */
605:
606: statint = 1000000 / stathz;
607: minint = statint / 2 + 100;
608: while (statvar > minint)
609: statvar >>= 1;
610:
611: /*
612: * Establish scheduler softint.
613: */
614: schedint.ih_pil = PIL_SCHED;
615: schedint.ih_clr = NULL;
616: schedint.ih_arg = 0;
617: schedint.ih_pending = 0;
618: schedhz = stathz/4;
619:
620: /*
621: * Enable timers
622: *
623: * Also need to map the interrupts cause we're not a child of the sbus.
624: * N.B. By default timer[0] is disabled and timer[1] is enabled.
625: */
626: stxa((vaddr_t)&timerreg_4u.t_timer[0].t_limit, ASI_NUCLEUS,
627: tmr_ustolim(tick)|TMR_LIM_IEN|TMR_LIM_PERIODIC|TMR_LIM_RELOAD);
628: stxa((vaddr_t)&timerreg_4u.t_mapintr[0], ASI_NUCLEUS,
629: timerreg_4u.t_mapintr[0]|INTMAP_V);
630:
631: #ifdef DEBUG
632: if (intrdebug)
633: /* Neglect to enable timer */
634: stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
635: tmr_ustolim(statint)|TMR_LIM_RELOAD);
636: else
637: #endif
638: stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
639: tmr_ustolim(statint)|TMR_LIM_IEN|TMR_LIM_RELOAD);
640: stxa((vaddr_t)&timerreg_4u.t_mapintr[1], ASI_NUCLEUS,
641: timerreg_4u.t_mapintr[1]|INTMAP_V);
642:
643: statmin = statint - (statvar >> 1);
644:
645: }
646:
647: /*
648: * Dummy setstatclockrate(), since we know profhz==hz.
649: */
650: /* ARGSUSED */
651: void
652: setstatclockrate(newhz)
653: int newhz;
654: {
655: /* nothing */
656: }
657:
658: /*
659: * Level 10 (clock) interrupts. If we are using the FORTH PROM for
660: * console input, we need to check for that here as well, and generate
661: * a software interrupt to read it.
662: */
663: #ifdef DEBUG
664: static int clockcheck = 0;
665: #endif
666: int
667: clockintr(cap)
668: void *cap;
669: {
670: #ifdef DEBUG
671: static int64_t tick_base = 0;
672: struct timeval ctime;
673: int64_t t;
674:
675: t = tick() & TICK_TICKS;
676:
677: microtime(&ctime);
678: if (!tick_base) {
679: tick_base = (ctime.tv_sec * 1000000LL + ctime.tv_usec)
680: * 1000000LL / cpu_clockrate;
681: tick_base -= t;
682: } else if (clockcheck) {
683: int64_t tk = t;
684: int64_t clk = (ctime.tv_sec * 1000000LL + ctime.tv_usec);
685: t -= tick_base;
686: t = t * 1000000LL / cpu_clockrate;
687: if (t - clk > hz) {
688: printf("Clock lost an interrupt!\n");
689: printf("Actual: %llx Expected: %llx tick %llx "
690: "tick_base %llx\n", (long long)t, (long long)clk,
691: (long long)tk, (long long)tick_base);
692: #ifdef DDB
693: Debugger();
694: #endif
695: tick_base = 0;
696: }
697: }
698: #endif
699: /* Let locore.s clear the interrupt for us. */
700: hardclock((struct clockframe *)cap);
701:
702: level10.ih_count.ec_count++;
703:
704: return (1);
705: }
706:
707: /*
708: * Level 10 (clock) interrupts. If we are using the FORTH PROM for
709: * console input, we need to check for that here as well, and generate
710: * a software interrupt to read it.
711: *
712: * %tick is really a level-14 interrupt. We need to remap this in
713: * locore.s to a level 10.
714: */
715: int
716: tickintr(cap)
717: void *cap;
718: {
719: int s;
720:
721: hardclock((struct clockframe *)cap);
722:
723: s = splhigh();
724: /* Reset the interrupt */
725: next_tick(tick_increment);
726: level0.ih_count.ec_count++;
727: splx(s);
728:
729: return (1);
730: }
731:
732: /*
733: * Level 14 (stat clock) interrupt handler.
734: */
735: int
736: statintr(cap)
737: void *cap;
738: {
739: u_long newint, r, var;
740: struct cpu_info *ci = curcpu();
741:
742: #ifdef NOT_DEBUG
743: printf("statclock: count %x:%x, limit %x:%x\n",
744: timerreg_4u.t_timer[1].t_count, timerreg_4u.t_timer[1].t_limit);
745: #endif
746: #ifdef NOT_DEBUG
747: prom_printf("!");
748: #endif
749: statclock((struct clockframe *)cap);
750: #ifdef NOTDEF_DEBUG
751: /* Don't re-schedule the IRQ */
752: return 1;
753: #endif
754: /*
755: * Compute new randomized interval. The intervals are uniformly
756: * distributed on [statint - statvar / 2, statint + statvar / 2],
757: * and therefore have mean statint, giving a stathz frequency clock.
758: */
759: var = statvar;
760: do {
761: r = random() & (var - 1);
762: } while (r == 0);
763: newint = statmin + r;
764:
765: if (schedhz)
766: if ((++ci->ci_schedstate.spc_schedticks & 3) == 0)
767: send_softint(-1, PIL_SCHED, &schedint);
768: stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS,
769: tmr_ustolim(newint)|TMR_LIM_IEN|TMR_LIM_RELOAD);
770:
771: level14.ih_count.ec_count++;
772:
773: return (1);
774: }
775:
776: int
777: schedintr(arg)
778: void *arg;
779: {
780: if (curproc)
781: schedclock(curproc);
782: return (1);
783: }
784:
785:
786: /*
787: * `sparc_clock_time_is_ok' is used in cpu_reboot() to determine
788: * whether it is appropriate to call resettodr() to consolidate
789: * pending time adjustments.
790: */
791: int sparc_clock_time_is_ok;
792:
793: /*
794: * Set up the system's time, given a `reasonable' time value.
795: */
796: void
797: inittodr(base)
798: time_t base;
799: {
800: int badbase = 0, waszero = base == 0;
801: char *bad = NULL;
802: struct timeval tv;
803: struct timespec ts;
804:
805: if (base < 5 * SECYR) {
806: /*
807: * If base is 0, assume filesystem time is just unknown
808: * in stead of preposterous. Don't bark.
809: */
810: if (base != 0)
811: printf("WARNING: preposterous time in file system\n");
812: /* not going to use it anyway, if the chip is readable */
813: base = 21*SECYR + 186*SECDAY + SECDAY/2;
814: badbase = 1;
815: }
816:
817: if (todr_handle && (todr_gettime(todr_handle, &tv) != 0 ||
818: tv.tv_sec == 0)) {
819: /*
820: * Believe the time in the file system for lack of
821: * anything better, resetting the clock.
822: */
823: bad = "WARNING: bad date in battery clock";
824: tv.tv_sec = base;
825: tv.tv_usec = 0;
826: if (!badbase)
827: resettodr();
828: } else {
829: int deltat = tv.tv_sec - base;
830:
831: sparc_clock_time_is_ok = 1;
832:
833: if (deltat < 0)
834: deltat = -deltat;
835: if (!(waszero || deltat < 2 * SECDAY)) {
836: #ifndef SMALL_KERNEL
837: printf("WARNING: clock %s %ld days",
838: tv.tv_sec < base ? "lost" : "gained", deltat / SECDAY);
839: bad = "";
840: #endif
841: }
842: }
843:
844: ts.tv_sec = tv.tv_sec;
845: ts.tv_nsec = tv.tv_usec * 1000;
846: tc_setclock(&ts);
847:
848: if (bad) {
849: printf("%s", bad);
850: printf(" -- CHECK AND RESET THE DATE!\n");
851: }
852: }
853:
854: /*
855: * Reset the clock based on the current time.
856: * Used when the current clock is preposterous, when the time is changed,
857: * and when rebooting. Do nothing if the time is not yet known, e.g.,
858: * when crashing during autoconfig.
859: */
860: void
861: resettodr()
862: {
863: struct timeval tv;
864:
865: if (time_second == 0)
866: return;
867:
868: microtime(&tv);
869:
870: sparc_clock_time_is_ok = 1;
871: if (todr_handle == 0 || todr_settime(todr_handle, &tv) != 0)
872: printf("Cannot set time in time-of-day clock\n");
873: }
874:
875: /*
876: * XXX: these may actually belong somewhere else, but since the
877: * EEPROM is so closely tied to the clock on some models, perhaps
878: * it needs to stay here...
879: */
880: int
881: eeprom_uio(uio)
882: struct uio *uio;
883: {
884: return (ENODEV);
885: }
886:
887: u_int
888: tick_get_timecount(struct timecounter *tc)
889: {
890: u_int64_t tick;
891:
892: __asm __volatile("rd %%tick, %0" : "=r" (tick) :);
893:
894: return (tick & ~0u);
895: }
CVSweb