summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2012-11-05 13:20:17 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2012-11-05 13:20:17 +0000
commit6bff42cbf2fd11eba1dd8f7fdbe75f50224908d9 (patch)
tree220955617386d1b0fc93d6cf09f4c82b78161b71
parentf7a0cb13b6e151a79031d716ba8cd21d874141f8 (diff)
Switch sparc to timecounters. Heavily based on NetBSD.
-rw-r--r--sys/arch/sparc/include/_types.h5
-rw-r--r--sys/arch/sparc/include/intr.h4
-rw-r--r--sys/arch/sparc/sparc/clock.c177
-rw-r--r--sys/arch/sparc/sparc/intr.c27
-rw-r--r--sys/arch/sparc/sparc/locore.s71
-rw-r--r--sys/arch/sparc/sparc/machdep.c5
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();
}
/*