diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2012-11-05 13:20:17 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2012-11-05 13:20:17 +0000 |
commit | 6bff42cbf2fd11eba1dd8f7fdbe75f50224908d9 (patch) | |
tree | 220955617386d1b0fc93d6cf09f4c82b78161b71 /sys/arch/sparc | |
parent | f7a0cb13b6e151a79031d716ba8cd21d874141f8 (diff) |
Switch sparc to timecounters. Heavily based on NetBSD.
Diffstat (limited to 'sys/arch/sparc')
-rw-r--r-- | sys/arch/sparc/include/_types.h | 5 | ||||
-rw-r--r-- | sys/arch/sparc/include/intr.h | 4 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/clock.c | 177 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/intr.c | 27 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/locore.s | 71 | ||||
-rw-r--r-- | sys/arch/sparc/sparc/machdep.c | 5 |
6 files changed, 135 insertions, 154 deletions
diff --git a/sys/arch/sparc/include/_types.h b/sys/arch/sparc/include/_types.h index cbdd9920bb8..71ae9ae0623 100644 --- a/sys/arch/sparc/include/_types.h +++ b/sys/arch/sparc/include/_types.h @@ -1,4 +1,4 @@ -/* $OpenBSD: _types.h,v 1.17 2012/04/28 17:24:50 miod Exp $ */ +/* $OpenBSD: _types.h,v 1.18 2012/11/05 13:20:16 miod Exp $ */ /*- * Copyright (c) 1990, 1993 @@ -143,4 +143,7 @@ typedef int __rune_t; typedef void * __wctrans_t; typedef void * __wctype_t; +/* Feature test macros */ +#define __HAVE_TIMECOUNTER + #endif /* _MACHINE__TYPES_H_ */ diff --git a/sys/arch/sparc/include/intr.h b/sys/arch/sparc/include/intr.h index f3f5cd83eed..8ab4b59ecc4 100644 --- a/sys/arch/sparc/include/intr.h +++ b/sys/arch/sparc/include/intr.h @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.h,v 1.3 2011/03/23 16:54:37 pirofti Exp $ */ +/* $OpenBSD: intr.h,v 1.4 2012/11/05 13:20:16 miod Exp $ */ /* $NetBSD: cpu.h,v 1.24 1997/03/15 22:25:15 pk Exp $ */ /* @@ -76,8 +76,6 @@ void vmeintr_establish(int, int, struct intrhand *, int, const char *); int intr_fasttrap(int, void (*)(void), int (*)(void *), void *); void intr_fastuntrap(int); -void intr_init(void); - /* * Soft interrupt handler chains. In addition to a struct intrhand for * proper dispatching, we also remember a pending state as well as the diff --git a/sys/arch/sparc/sparc/clock.c b/sys/arch/sparc/sparc/clock.c index 382b3266470..56eee62e412 100644 --- a/sys/arch/sparc/sparc/clock.c +++ b/sys/arch/sparc/sparc/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.26 2010/07/10 19:32:24 miod Exp $ */ +/* $OpenBSD: clock.c,v 1.27 2012/11/05 13:20:16 miod Exp $ */ /* $NetBSD: clock.c,v 1.52 1997/05/24 20:16:05 pk Exp $ */ /* @@ -67,6 +67,7 @@ #include <sys/resourcevar.h> #include <sys/malloc.h> #include <sys/systm.h> +#include <sys/timetc.h> #ifdef GPROF #include <sys/gmon.h> #endif @@ -125,7 +126,6 @@ long oclk_get_secs(void); void oclk_get_dt(struct intersil_dt *); void oclk_set_dt(struct intersil_dt *); void oclk_set_secs(long); -#endif int oclockmatch(struct device *, void *, void *); void oclockattach(struct device *, struct device *, void *); @@ -138,6 +138,15 @@ struct cfdriver oclock_cd = { NULL, "oclock", DV_DULL }; +u_int oclock_get_timecount(struct timecounter *); +struct timecounter oclock_timecounter = { + .tc_get_timecount = oclock_get_timecount, + .tc_counter_mask = 0xffffffff, + .tc_name = "oclock", + .tc_quality = 0 +}; +#endif + /* * Sun 4 machines use the old-style (a'la Sun 3) EEPROM. On the * 4/100's and 4/200's, this is at a separate obio space. On the @@ -194,11 +203,34 @@ struct cfdriver timer_cd = { NULL, "timer", DV_DULL }; +/* + * timecounter local state + */ +static struct counter { + volatile u_int *cntreg; /* counter register */ + u_int limit; /* limit we count up to */ + u_int offset; /* accumulated offset due to wraps */ + u_int shift; /* scaling for valid bits */ +} cntr; + +u_int timer_get_timecount(struct timecounter *); +struct timecounter timer_timecounter = { + .tc_get_timecount = timer_get_timecount, + .tc_counter_mask = 0xffffffff, + .tc_name = "counter-timer", + .tc_quality = 100, + .tc_priv = &cntr +}; + void clk_wenable(int); void myetheraddr(u_char *); int timerblurb = 10; /* Guess a value; used before clock is attached */ +static struct intrhand level10 = { .ih_fun = clockintr, .ih_arg = NULL }; +static struct intrhand level14 = { .ih_fun = statintr, .ih_arg = NULL }; + +#if defined(SUN4) /* * old clock match routine */ @@ -232,7 +264,6 @@ oclockattach(parent, self, aux) struct device *parent, *self; void *aux; { -#if defined(SUN4) struct confargs *ca = aux; struct romaux *ra = &ca->ca_ra; struct idprom *idp; @@ -266,7 +297,7 @@ oclockattach(parent, self, aux) ival = *ireg; /* clear, save value */ intersil_disable(i7); /* disable clock */ if (ival & INTERSIL_INTER_PENDING) { - printf(" delay constant %d%s\n", timerblurb, + printf(": delay constant %d%s\n", timerblurb, (timerblurb == 1) ? " [TOO SMALL?]" : ""); break; } @@ -276,9 +307,21 @@ oclockattach(parent, self, aux) break; } } -#endif /* SUN4 */ + + oclock_timecounter.tc_frequency = hz; + tc_init(&oclock_timecounter); + + intr_establish(10, &level10, IPL_CLOCK, "clock"); + intr_establish(14, &level14, IPL_STATCLOCK, "prof"); } +u_int +oclock_get_timecount(struct timecounter *tc) +{ + return level10.ih_count.ec_count; +} +#endif /* SUN4 */ + /* * Sun 4/100, 4/200 EEPROM match routine. */ @@ -475,6 +518,7 @@ timerattach(parent, self, aux) struct romaux *ra = &ca->ca_ra; volatile int *cnt = NULL, *lim = NULL; /* XXX: must init to NULL to avoid stupid gcc -Wall warning */ + u_int prec = 0, t0; if (CPU_ISSUN4M) { (void)mapdev(&ra->ra_reg[ra->ra_nreg-1], TIMERREG_VA, 0, @@ -487,21 +531,22 @@ timerattach(parent, self, aux) /* Put processor counter in "timer" mode */ timerreg_4m->t_cfg = 0; - cnt = &counterreg_4m->t_counter; - lim = &counterreg_4m->t_limit; + cnt = &timerreg_4m->t_counter; + lim = &timerreg_4m->t_limit; } if (CPU_ISSUN4OR4COR4E) { /* * This time, we ignore any existing virtual address because * we have a fixed virtual address for the timer, to make - * microtime() faster (in SUN4/SUN4C/SUN4E kernel only). + * time counter operation faster (in SUN4/SUN4C/SUN4E kernel + * only). */ (void)mapdev(ra->ra_reg, TIMERREG_VA, 0, sizeof(struct timerreg_4)); - cnt = &timerreg4->t_c14.t_counter; - lim = &timerreg4->t_c14.t_limit; + cnt = &timerreg4->t_c10.t_counter; + lim = &timerreg4->t_c10.t_limit; } timerok = 1; @@ -514,7 +559,7 @@ timerattach(parent, self, aux) for (timerblurb = 1; ; timerblurb++) { volatile int discard; - int t0, t1; + u_int t1; /* Reset counter register by writing some large limit value */ discard = *lim; @@ -524,6 +569,8 @@ timerattach(parent, self, aux) delay(100); t1 = *cnt; + prec |= (t0 ^ t1) | (*cnt ^ *cnt); + if (t1 & TMR_LIMIT) panic("delay calibration"); @@ -535,9 +582,43 @@ timerattach(parent, self, aux) } - printf(" delay constant %d\n", timerblurb); + /* find lowest active bit */ + for (t0 = 0; t0 < TMR_SHIFT; t0++) + if ((1 << t0) & prec) + break; + + cntr.shift = t0; + cntr.limit = tick << (TMR_SHIFT - cntr.shift); + cntr.cntreg = cnt; + timer_timecounter.tc_frequency = 1000000 << (TMR_SHIFT - cntr.shift); + tc_init(&timer_timecounter); + + printf(": delay constant %d, frequency %llu Hz\n", + timerblurb, (unsigned long long)timer_timecounter.tc_frequency); + + intr_establish(10, &level10, IPL_CLOCK, "clock"); + intr_establish(14, &level14, IPL_STATCLOCK, "prof"); +} + +u_int +timer_get_timecount(struct timecounter *tc) +{ + struct counter *ctr = (struct counter *)tc->tc_priv; + u_int carry, cnt, res; + int s; + + s = splhigh(); + res = cnt = *ctr->cntreg; + res &= ~TMR_LIMIT; + if (cnt != res) + carry = ctr->limit; /* a clock interrupt is pending */ + else + carry = 0; + res >>= ctr->shift; + res += carry + ctr->offset; + splx(s); - /* should link interrupt handlers here, rather than compiled-in? */ + return res; } /* @@ -712,9 +793,15 @@ clockintr(cap) #if defined(SUN4) forward: #endif + cntr.offset += cntr.limit; splx(s); - hardclock((struct clockframe *)cap); + /* + * XXX Clock interrupts are enabled (and therefore serviceable) + * XXX before initclocks() has completed. + */ + if (cold == 0) + hardclock((struct clockframe *)cap); return (1); } @@ -785,6 +872,9 @@ inittodr(base) struct clock_ymdhms dt; int badbase = 0, waszero = base == 0; char *bad = NULL; + struct timespec ts; + + ts.tv_sec = ts.tv_nsec = 0; if (base < 5 * SECYR) { /* @@ -794,12 +884,12 @@ inittodr(base) if (base != 0) printf("WARNING: preposterous time in file system\n"); /* not going to use it anyway, if the chip is readable */ - base = 21*SECYR + 186*SECDAY + SECDAY/2; + base = (2012 - 1970) * SECYR; badbase = 1; } #if defined(SUN4) if (oldclk) { - time.tv_sec = oclk_get_secs(); + ts.tv_sec = oclk_get_secs(); goto forward; } #endif @@ -813,23 +903,25 @@ inittodr(base) dt.dt_year = FROMBCD(cl->cl_year) + CLOCK_BASE_YEAR; cl->cl_csr &= ~CLK_READ; /* time wears on */ clk_wenable(0); - time.tv_sec = clock_ymdhms_to_secs(&dt); + ts.tv_sec = clock_ymdhms_to_secs(&dt); #if defined(SUN4) forward: #endif - if (time.tv_sec == 0) { + if (ts.tv_sec == 0) { /* * Believe the time in the file system for lack of * anything better, resetting the clock. */ bad = "WARNING: bad date in battery clock"; - time.tv_sec = base; + ts.tv_sec = base; + tc_setclock(&ts); if (!badbase) resettodr(); } else { - int deltat = time.tv_sec - base; + int deltat = ts.tv_sec - base; + tc_setclock(&ts); if (deltat < 0) deltat = -deltat; if (waszero || deltat < 2 * SECDAY) @@ -837,7 +929,7 @@ forward: #ifndef SMALL_KERNEL printf("WARNING: clock %s %d days", - time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); + ts.tv_sec < base ? "lost" : "gained", deltat / SECDAY); bad = ""; #endif } @@ -861,17 +953,17 @@ resettodr() #if defined(SUN4) if (oldclk) { - if (!time.tv_sec || i7 == NULL) + if (!time_second || i7 == NULL) return; - oclk_set_secs(time.tv_sec); + oclk_set_secs(time_second); return; } #endif - if (!time.tv_sec || (cl = clockreg) == NULL) + if (!time_second || (cl = clockreg) == NULL) return; - clock_secs_to_ymdhms(time.tv_sec, &dt); + clock_secs_to_ymdhms(time_second, &dt); clk_wenable(1); cl->cl_csr |= CLK_WRITE; /* enable write */ @@ -979,41 +1071,6 @@ oclk_set_dt(dt) } #endif /* SUN4 */ -#if defined(SUN4) -/* - * Return the best possible estimate of the time in the timeval - * to which tvp points. We do this by returning the current time - * plus the amount of time since the last clock interrupt. - * - * Check that this time is no less than any previously-reported time, - * which could happen around the time of a clock adjustment. Just for - * fun, we guarantee that the time will be greater than the value - * obtained by a previous call. - */ -void -microtime(tvp) - struct timeval *tvp; -{ - int s; - static struct timeval lasttime; - static struct timeval oneusec = {0, 1}; - - if (!oldclk) { - lo_microtime(tvp); - return; - } - - s = splhigh(); - *tvp = time; - splx(s); - - if (timercmp(tvp, &lasttime, <=)) - timeradd(&lasttime, &oneusec, tvp); - - lasttime = *tvp; -} -#endif /* SUN4 */ - /* * XXX: these may actually belong somewhere else, but since the * EEPROM is so closely tied to the clock on some models, perhaps diff --git a/sys/arch/sparc/sparc/intr.c b/sys/arch/sparc/sparc/intr.c index 139ada0343a..934b3db70dc 100644 --- a/sys/arch/sparc/sparc/intr.c +++ b/sys/arch/sparc/sparc/intr.c @@ -1,4 +1,4 @@ -/* $OpenBSD: intr.c,v 1.37 2010/12/21 14:56:24 claudio Exp $ */ +/* $OpenBSD: intr.c,v 1.38 2012/11/05 13:20:16 miod Exp $ */ /* $NetBSD: intr.c,v 1.20 1997/07/29 09:42:03 fair Exp $ */ /* @@ -74,24 +74,22 @@ void strayintr(fp) struct clockframe *fp; { - static int straytime, nstray; - int timesince; + static int nstray; + static time_t straytime; + time_t timesince; printf("stray interrupt ipl 0x%x pc=0x%x npc=0x%x psr=%b\n", fp->ipl, fp->pc, fp->npc, fp->psr, PSR_BITS); - timesince = time.tv_sec - straytime; + timesince = time_second - straytime; if (timesince <= 10) { if (++nstray > 9) panic("crazy interrupts"); } else { - straytime = time.tv_sec; + straytime = time_second; nstray = 1; } } -static struct intrhand level10 = { clockintr, NULL, (IPL_CLOCK << 8) }; -static struct intrhand level14 = { statintr, NULL, (IPL_STATCLOCK << 8) }; - #if defined(SUN4M) void nmi_hard(void); void @@ -155,15 +153,6 @@ nmi_hard() } #endif -void -intr_init() -{ - level10.ih_vec = level10.ih_ipl >> 8; - evcount_attach(&level10.ih_count, "clock", &level10.ih_vec); - level14.ih_vec = level14.ih_ipl >> 8; - evcount_attach(&level14.ih_count, "prof", &level14.ih_vec); -} - /* * Level 15 interrupts are special, and not vectored here. * Only `prewired' interrupts appear here; boot-time configured devices @@ -180,11 +169,11 @@ struct intrhand *intrhand[15] = { NULL, /* 7 = video + SBus level 5 */ NULL, /* 8 = SBus level 6 */ NULL, /* 9 = SBus level 7 */ - &level10, /* 10 = counter 0 = clock */ + NULL, /* 10 = counter 0 = clock */ NULL, /* 11 = floppy */ NULL, /* 12 = zs hardware interrupt */ NULL, /* 13 = audio chip */ - &level14, /* 14 = counter 1 = profiling timer */ + NULL, /* 14 = counter 1 = profiling timer */ }; /* diff --git a/sys/arch/sparc/sparc/locore.s b/sys/arch/sparc/sparc/locore.s index 60d18dce690..7f970cda8e7 100644 --- a/sys/arch/sparc/sparc/locore.s +++ b/sys/arch/sparc/sparc/locore.s @@ -1,4 +1,4 @@ -/* $OpenBSD: locore.s,v 1.90 2011/07/04 22:53:53 tedu Exp $ */ +/* $OpenBSD: locore.s,v 1.91 2012/11/05 13:20:16 miod Exp $ */ /* $NetBSD: locore.s,v 1.73 1997/09/13 20:36:48 pk Exp $ */ /* @@ -3854,7 +3854,9 @@ Lgandul: nop b,a 2f 1: - MUNGE(NOP_ON_4_4C_1) +#if 0 /* until NOP_ON_4_4C labels reappear */ + MUNGE(NOP_ON_4_4C_...) +#endif 2: @@ -5800,71 +5802,6 @@ Lumul_shortway: addcc %g0, %g0, %o1 ! %o1 = zero, and set Z /* - * void lo_microtime(struct timeval *tv) - * - * LBL's sparc bsd 'microtime': We don't need to spl (so this routine - * can be a leaf routine) and we don't keep a 'last' timeval (there - * can't be two calls to this routine in a microsecond). This seems to - * be about 20 times faster than the Sun code on an SS-2. - vj - * - * Read time values from slowest-changing to fastest-changing, - * then re-read out to slowest. If the values read before - * the innermost match those read after, the innermost value - * is consistent with the outer values. If not, it may not - * be and we must retry. Typically this loop runs only once; - * occasionally it runs twice, and only rarely does it run longer. - */ -#if defined(SUN4) -ENTRY(lo_microtime) -#else -ENTRY(microtime) -#endif - sethi %hi(_C_LABEL(time)), %g2 - -#if (defined(SUN4D) || defined(SUN4M)) && !(defined(SUN4) || defined(SUN4C) || defined(SUN4E)) - sethi %hi(TIMERREG_VA+4), %g3 - or %g3, %lo(TIMERREG_VA+4), %g3 -#elif (defined(SUN4) || defined(SUN4C) || defined(SUN4E)) && !(defined(SUN4D) || defined(SUN4M)) - sethi %hi(TIMERREG_VA), %g3 - or %g3, %lo(TIMERREG_VA), %g3 -#else - sethi %hi(TIMERREG_VA), %g3 - or %g3, %lo(TIMERREG_VA), %g3 -NOP_ON_4_4C_1: - add %g3, 4, %g3 -#endif - -2: - ldd [%g2+%lo(_C_LABEL(time))], %o2 ! time.tv_sec & time.tv_usec - ld [%g3], %o4 ! usec counter - ldd [%g2+%lo(_C_LABEL(time))], %g4 ! see if time values changed - cmp %g4, %o2 - bne 2b ! if time.tv_sec changed - cmp %g5, %o3 - bne 2b ! if time.tv_usec changed - tst %o4 - - bpos 3f ! reached limit? - srl %o4, TMR_SHIFT, %o4 ! convert counter to usec - sethi %hi(_C_LABEL(tick)), %g4 ! bump usec by 1 tick - ld [%g4+%lo(_C_LABEL(tick))], %o1 - set TMR_MASK, %g5 - add %o1, %o3, %o3 - and %o4, %g5, %o4 -3: - add %o4, %o3, %o3 - set 1000000, %g5 ! normalize usec value - cmp %o3, %g5 - bl,a 4f - st %o2, [%o0] ! (should be able to std here) - add %o2, 1, %o2 ! overflow - sub %o3, %g5, %o3 - st %o2, [%o0] ! (should be able to std here) -4: - retl - st %o3, [%o0+4] - -/* * delay function * * void delay(N) -- delay N microseconds diff --git a/sys/arch/sparc/sparc/machdep.c b/sys/arch/sparc/sparc/machdep.c index e4b18e289b1..1c4c21164db 100644 --- a/sys/arch/sparc/sparc/machdep.c +++ b/sys/arch/sparc/sparc/machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: machdep.c,v 1.142 2012/10/22 17:28:27 kettenis Exp $ */ +/* $OpenBSD: machdep.c,v 1.143 2012/11/05 13:20:16 miod Exp $ */ /* $NetBSD: machdep.c,v 1.85 1997/09/12 08:55:02 pk Exp $ */ /* @@ -208,9 +208,6 @@ cpu_startup() * Set up buffers, so they can be used to read disk labels. */ bufinit(); - - /* Early interrupt handlers initialization */ - intr_init(); } /* |