diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2012-11-04 13:33:33 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2012-11-04 13:33:33 +0000 |
commit | 00f1afe558f65aa2a73264f45ff09404b4ca0d27 (patch) | |
tree | 8ffe265d42e9f57c989a6d3e57997a4cf79fcce3 /sys/arch/mvme68k/dev | |
parent | c1ecdcae04c1aa563107dfacf8594c62ffea2c71 (diff) |
Switch mvme68k to timecounters.
Diffstat (limited to 'sys/arch/mvme68k/dev')
-rw-r--r-- | sys/arch/mvme68k/dev/cl.c | 6 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/clock.c | 261 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/mcreg.h | 3 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/nvram.c | 63 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/pccreg.h | 9 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/pcctworeg.h | 3 | ||||
-rw-r--r-- | sys/arch/mvme68k/dev/wl.c | 6 |
7 files changed, 288 insertions, 63 deletions
diff --git a/sys/arch/mvme68k/dev/cl.c b/sys/arch/mvme68k/dev/cl.c index 75cabd57771..c92b40ea208 100644 --- a/sys/arch/mvme68k/dev/cl.c +++ b/sys/arch/mvme68k/dev/cl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: cl.c,v 1.52 2010/06/28 14:13:29 deraadt Exp $ */ +/* $OpenBSD: cl.c,v 1.53 2012/11/04 13:33:32 miod Exp $ */ /* * Copyright (c) 1995 Dale Rahn. All rights reserved. @@ -1790,11 +1790,11 @@ time_t *ptime; u_char *msg; { /* - if (*ptime != time.tv_sec) { + if (*ptime != time_second) { */ { /* - *ptime = time.tv_sec; + *ptime = time_second; */ log(LOG_WARNING, "%s%d[%d]: %s overrun\n", cl_cd.cd_name, 0 /* fix */, channel, msg); diff --git a/sys/arch/mvme68k/dev/clock.c b/sys/arch/mvme68k/dev/clock.c index 0963ee132c8..2540be51ae6 100644 --- a/sys/arch/mvme68k/dev/clock.c +++ b/sys/arch/mvme68k/dev/clock.c @@ -1,4 +1,4 @@ -/* $OpenBSD: clock.c,v 1.16 2009/03/01 22:08:13 miod Exp $ */ +/* $OpenBSD: clock.c,v 1.17 2012/11/04 13:33:32 miod Exp $ */ /* * Copyright (c) 1995 Theo de Raadt @@ -67,6 +67,7 @@ #include <sys/device.h> #include <sys/kernel.h> #include <sys/systm.h> +#include <sys/timetc.h> #include <machine/psl.h> #include <machine/autoconf.h> @@ -167,6 +168,8 @@ clockattach(parent, self, args) /* * XXX once we have dynamic ipl levels, put clock at ipl 6, * move it to timer1, then use timer2/ipl5 for statclock. + * But then time counters will need to be implemented + * differently. */ lrcintr_establish(LRCVEC_TIMER2, &sc->sc_profih, "clock"); break; @@ -181,7 +184,12 @@ clockattach(parent, self, args) #endif #if NOFOBIO > 0 case BUS_OFOBIO: + { + extern struct timecounter ofobio_timecounter; /* below */ + + ofobio_timecounter.tc_priv = sc; intr_establish(OFOBIOVEC_CLOCK, &sc->sc_profih, "clock"); + } break; #endif #if NPCC > 0 @@ -205,6 +213,172 @@ clockattach(parent, self, args) printf("\n"); } +#if NLRC > 0 +u_int lrc_get_timecount(struct timecounter *); +struct timecounter lrc_timecounter = { + .tc_get_timecount = lrc_get_timecount, + .tc_counter_mask = 0x00ffffff, /* 24-bit timer */ + .tc_frequency = 1000000, /* 1MHz */ + .tc_name = "lrc", + .tc_quality = 100 +}; + +u_int +lrc_get_timecount(struct timecounter *tc) +{ + /* + * Because LRC timers start counting at one, we need to count + * wraparounds, and subtract the number of wraparounds, since + * we go from FFFFFF to 000001. + */ + static u_int lrc_wraparounds = 0; + static uint32_t lrc_last = 0; + uint32_t lrc_cur; + + lrc_cur = sys_lrc->lrc_t1cnt & 0x00ffffff; + if (lrc_cur < lrc_last) + lrc_wraparounds++; + lrc_last = lrc_cur; + + return lrc_cur - lrc_wraparounds; +} +#endif + +#if NMC > 0 +u_int mc_get_timecount(struct timecounter *); +struct timecounter mc_timecounter = { + .tc_get_timecount = mc_get_timecount, + .tc_counter_mask = 0xffffffff, /* 32-bit timer */ + .tc_frequency = 1000000, /* 1MHz */ + .tc_name = "mc", + .tc_quality = 100 +}; + +u_int +mc_get_timecount(struct timecounter *tc) +{ + /* + * Note that, theoretically, we ought to check for counter overflows. + * However, this timer is free-running with a rollover period of 71.6 + * minutes - if two time counter readings are separated by more than + * this amount, there are more important issues to take care of first. + */ + return sys_mc->mc_t3count; +} +#endif + +#if NOFOBIO > 0 +u_int ofobio_get_timecount(struct timecounter *); +struct timecounter ofobio_timecounter = { + .tc_get_timecount = ofobio_get_timecount, + .tc_counter_mask = 0xffffffff, + /* .tc_frequency will be filled in */ + .tc_name = "ofobio", + .tc_quality = 0 +}; + +u_int +ofobio_get_timecount(struct timecounter *tc) +{ + struct clocksoftc *sc = tc->tc_priv; + + /* + * XXX It should be possible to get a better resolution by + * XXX peeking at the DART internal state, but the way this + * XXX clock is wired is horrible enough as is. + */ + return sc->sc_profih.ih_count.ec_count; +} +#endif + +#if NPCC > 0 +u_int pcc_get_timecount(struct timecounter *); +uint32_t pcc_curcnt; +struct timecounter pcc_timecounter = { + .tc_get_timecount = pcc_get_timecount, + .tc_counter_mask = 0xffffffff, /* 32-bit timer */ + .tc_frequency = PCC_TIMERFREQ, + .tc_name = "pcc", + .tc_quality = 100 +}; + +u_int +pcc_get_timecount(struct timecounter *tc) +{ + uint16_t tcr1, tcr2, pload; + uint8_t tctl; + u_int cnt; + int s; + + pload = sys_pcc->pcc_t1pload; + s = splclock(); + tcr1 = sys_pcc->pcc_t1count; + tctl = sys_pcc->pcc_t1ctl; + /* + * Since we can not freeze the counter while reading the count + * and overflow registers, read them a second time; if the counter + * has wrapped, pick the second reading. + */ + tcr2 = sys_pcc->pcc_t1count; + if (tcr2 < tcr1) { + tcr1 = tcr2; + tctl = sys_pcc->pcc_t1ctl; + } + cnt = pcc_curcnt; + splx(s); + tctl >>= PCC_TIMER_OVF_SHIFT; + while (tctl-- != 0) + cnt += 0x10000U - pload; + cnt += tcr1 - pload; + + return cnt; +} +#endif + +#if NPCCTWO > 0 +u_int pcctwo_get_timecount(struct timecounter *); +uint32_t pcctwo_curcnt; +struct timecounter pcctwo_timecounter = { + .tc_get_timecount = pcctwo_get_timecount, + .tc_counter_mask = 0xffffffff, /* 32-bit timer */ + .tc_frequency = 1000000, /* 1MHz */ + .tc_name = "pcctwo", + .tc_quality = 100 +}; + +u_int +pcctwo_get_timecount(struct timecounter *tc) +{ + uint32_t tcr1, tcr2; + uint8_t tctl; + u_int cnt, cmp; + int s; + + cmp = sys_pcc2->pcc2_t1cmp; + s = splclock(); + tcr1 = sys_pcc2->pcc2_t1count; + tctl = sys_pcc2->pcc2_t1ctl; + /* + * Since we can not freeze the counter while reading the count + * and overflow registers, read them a second time; if the counter + * has wrapped, pick the second reading. + */ + tcr2 = sys_pcc2->pcc2_t1count; + if (tcr2 < tcr1) { + tcr1 = tcr2; + tctl = sys_pcc2->pcc2_t1ctl; + } + cnt = pcctwo_curcnt; + splx(s); + tctl >>= PCC2_TCTL_OVF_SHIFT; + while (tctl-- != 0) + cnt += cmp; + cnt += tcr1; + + return cnt; +} +#endif + /* * clockintr: ack intr and call hardclock */ @@ -212,6 +386,12 @@ int clockintr(arg) void *arg; { + u_int oflow = 1; +#if NMC > 0 || NPCC > 0 || NPCCTWO > 0 + uint32_t t1, t2; + uint8_t c; +#endif + switch (clockbus) { #if NLRC > 0 case BUS_LRC: @@ -225,22 +405,63 @@ clockintr(arg) #endif #if NMC > 0 case BUS_MC: + /* + * Since we can not freeze the counter while reading the count + * and overflow registers, read them a second time; if the + * counter has wrapped, pick the second reading. + */ + t1 = sys_mc->mc_t1count; + c = sys_mc->mc_t1ctl; + t2 = sys_mc->mc_t1count; + if (t2 < t1) /* just wrapped */ + c = sys_mc->mc_t1ctl; + sys_mc->mc_t1ctl = MC_TCTL_CEN | MC_TCTL_COC | MC_TCTL_COVF; sys_mc->mc_t1irq = prof_reset; + oflow = c >> MC_TCTL_OVF_SHIFT; break; #endif #if NPCC > 0 case BUS_PCC: + /* + * Since we can not freeze the counter while reading the count + * and overflow registers, read them a second time; if the + * counter has wrapped, pick the second reading. + */ + t1 = sys_pcc->pcc_t1count; + c = sys_pcc->pcc_t1ctl; + t2 = sys_pcc->pcc_t1count; + if (t2 < t1) /* just wrapped */ + c = sys_pcc->pcc_t1ctl; + sys_pcc->pcc_t1ctl = PCC_TIMER_COVF | PCC_TIMERSTART; sys_pcc->pcc_t1irq = prof_reset; + oflow = c >> PCC_TIMER_OVF_SHIFT; + pcc_curcnt += oflow * (0x10000 - sys_pcc->pcc_t1pload); break; #endif #if NPCCTWO > 0 case BUS_PCCTWO: + /* + * Since we can not freeze the counter while reading the count + * and overflow registers, read them a second time; if the + * counter has wrapped, pick the second reading. + */ + t1 = sys_pcc2->pcc2_t1count; + c = sys_pcc2->pcc2_t1ctl; + t2 = sys_pcc2->pcc2_t1count; + if (t2 < t1) /* just wrapped */ + c = sys_pcc2->pcc2_t1ctl; + sys_pcc2->pcc2_t1ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC | + PCC2_TCTL_COVF; sys_pcc2->pcc2_t1irq = prof_reset; + oflow = c >> PCC2_TCTL_OVF_SHIFT; + pcctwo_curcnt += oflow * sys_pcc2->pcc2_t1cmp; break; #endif } - hardclock(arg); + while (oflow-- != 0) + hardclock(arg); + return (1); } @@ -274,12 +495,21 @@ cpu_initclocks() case BUS_LRC: profhz = stathz = 0; /* only one timer available for now */ + /* + * LRC timer usage: + * timer0 is used for delay(). + * timer1 is used for time counters. + * timer2 is used for the scheduling clock. + */ sys_lrc->lrc_tcr0 = 0; - sys_lrc->lrc_tcr1 = 0; - /* profclock as timer 2 */ + sys_lrc->lrc_tcr1 = TCR_TLD1; /* reset to one */ + sys_lrc->lrc_tcr1 = TCR_TEN1 | TCR_TCYC1 | TCR_TIS_NONE; + sys_lrc->lrc_t2base = tick + 1; sys_lrc->lrc_tcr2 = TCR_TLD2; /* reset to one */ sys_lrc->lrc_tcr2 = TCR_TEN2 | TCR_TCYC2 | TCR_T2IE; + + tc_init(&lrc_timecounter); break; #endif #if NOFOBIO > 0 @@ -287,23 +517,38 @@ cpu_initclocks() profhz = stathz = 0; /* only one timer available */ ofobio_clocksetup(); + + ofobio_timecounter.tc_frequency = hz; + tc_init(&ofobio_timecounter); break; #endif #if NMC > 0 case BUS_MC: - /* profclock */ + /* + * MC timer usage: + * timer1 is used for the scheduling clock. + * timer2 is used for the statistics clock. + * timer3 is used for time counters. + */ + sys_mc->mc_t1ctl = 0; sys_mc->mc_t1cmp = mc_timer_us2lim(tick); sys_mc->mc_t1count = 0; sys_mc->mc_t1ctl = MC_TCTL_CEN | MC_TCTL_COC | MC_TCTL_COVF; sys_mc->mc_t1irq = prof_reset; - /* statclock */ sys_mc->mc_t2ctl = 0; sys_mc->mc_t2cmp = mc_timer_us2lim(statint); sys_mc->mc_t2count = 0; sys_mc->mc_t2ctl = MC_TCTL_CEN | MC_TCTL_COC | MC_TCTL_COVF; sys_mc->mc_t2irq = stat_reset; + + sys_mc->mc_t3ctl = 0; + sys_mc->mc_t3cmp = 0; + sys_mc->mc_t3count = 0; + sys_mc->mc_t3ctl = MC_TCTL_CEN; + sys_mc->mc_t3irq = 0; + tc_init(&mc_timecounter); break; #endif #if NPCC > 0 @@ -317,6 +562,8 @@ cpu_initclocks() sys_pcc->pcc_t2ctl = PCC_TIMERCLEAR; sys_pcc->pcc_t2ctl = PCC_TIMERSTART; sys_pcc->pcc_t2irq = stat_reset; + + tc_init(&pcc_timecounter); break; #endif #if NPCCTWO > 0 @@ -336,6 +583,8 @@ cpu_initclocks() sys_pcc2->pcc2_t2ctl = PCC2_TCTL_CEN | PCC2_TCTL_COC | PCC2_TCTL_COVF; sys_pcc2->pcc2_t2irq = stat_reset; + + tc_init(&pcctwo_timecounter); break; #endif } diff --git a/sys/arch/mvme68k/dev/mcreg.h b/sys/arch/mvme68k/dev/mcreg.h index c70c69fe78c..61842281712 100644 --- a/sys/arch/mvme68k/dev/mcreg.h +++ b/sys/arch/mvme68k/dev/mcreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: mcreg.h,v 1.9 2004/07/30 22:29:45 miod Exp $ */ +/* $OpenBSD: mcreg.h,v 1.10 2012/11/04 13:33:32 miod Exp $ */ /* * Copyright (c) 1995 Theo de Raadt @@ -137,6 +137,7 @@ extern struct mcreg *sys_mc; #define MC_TCTL_COC 0x02 #define MC_TCTL_COVF 0x04 #define MC_TCTL_OVF 0xf0 +#define MC_TCTL_OVF_SHIFT 4 #define MC_ABORT_ABS 0x40 diff --git a/sys/arch/mvme68k/dev/nvram.c b/sys/arch/mvme68k/dev/nvram.c index 38e548ca4aa..3f29c1a2d7c 100644 --- a/sys/arch/mvme68k/dev/nvram.c +++ b/sys/arch/mvme68k/dev/nvram.c @@ -1,4 +1,4 @@ -/* $OpenBSD: nvram.c,v 1.21 2010/12/26 15:40:59 miod Exp $ */ +/* $OpenBSD: nvram.c,v 1.22 2012/11/04 13:33:32 miod Exp $ */ /* * Copyright (c) 1995 Theo de Raadt @@ -35,6 +35,7 @@ #include <sys/kernel.h> #include <sys/ioctl.h> #include <sys/device.h> +#include <sys/timetc.h> #include <machine/autoconf.h> #include <machine/conf.h> @@ -47,10 +48,6 @@ #include <mvme68k/dev/memdevs.h> #include <mvme68k/dev/nvramreg.h> -#if defined(GPROF) -#include <sys/gmon.h> -#endif - struct nvramsoftc { struct device sc_dev; paddr_t sc_paddr; @@ -139,38 +136,6 @@ nvramattach(parent, self, args) } /* - * 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 (clock.c:clkread). - * - * 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) - register struct timeval *tvp; -{ - int s = splhigh(); - static struct timeval lasttime; - - *tvp = time; - while (tvp->tv_usec >= 1000000) { - tvp->tv_sec++; - tvp->tv_usec -= 1000000; - } - if (tvp->tv_sec == lasttime.tv_sec && - tvp->tv_usec <= lasttime.tv_usec && - (tvp->tv_usec = lasttime.tv_usec + 1) >= 1000000) { - tvp->tv_sec++; - tvp->tv_usec -= 1000000; - } - lasttime = *tvp; - splx(s); -} - -/* * BCD to decimal and decimal to BCD. */ #define FROMBCD(x) (((x) >> 4) * 10 + ((x) & 0xf)) @@ -240,7 +205,7 @@ void timetochip(c) struct chiptime *c; { - int t, t2, t3, now = time.tv_sec; + int t, t2, t3, now = time_second; /* January 1 1970 was a Thursday (4 in unix wdays) */ /* compute the days since the epoch */ @@ -295,8 +260,11 @@ inittodr(base) struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0]; int sec, min, hour, day, mon, year; int badbase = 0, waszero = base == 0; + struct timespec ts; - if (base < 5 * SECYR) { + ts.tv_sec = ts.tv_nsec = 0; + + if (base < (2012 - 1970) * SECYR) { /* * If base is 0, assume filesystem time is just unknown * instead of preposterous. Don't bark. @@ -304,7 +272,7 @@ 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; } @@ -335,24 +303,27 @@ inittodr(base) cl->cl_csr &= ~CLK_READ; /* time wears on */ } - if ((time.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) { + if ((ts.tv_sec = chiptotime(sec, min, hour, day, mon, year)) == 0) { printf("WARNING: bad date in nvram"); /* * Believe the time in the file system for lack of * anything better, resetting the 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) return; printf("WARNING: clock %s %d days", - time.tv_sec < base ? "lost" : "gained", deltat / SECDAY); + ts.tv_sec < base ? "lost" : "gained", deltat / SECDAY); } printf(" -- CHECK AND RESET THE DATE!\n"); } @@ -366,10 +337,10 @@ inittodr(base) void resettodr() { - struct nvramsoftc *sc = (struct nvramsoftc *) nvram_cd.cd_devs[0]; + struct nvramsoftc *sc = (struct nvramsoftc *)nvram_cd.cd_devs[0]; struct chiptime c; - if (!time.tv_sec || sc->sc_clockregs == NULL) + if (!time_second || sc == NULL || sc->sc_clockregs == NULL) return; timetochip(&c); diff --git a/sys/arch/mvme68k/dev/pccreg.h b/sys/arch/mvme68k/dev/pccreg.h index eea8f9126d4..7886617e02f 100644 --- a/sys/arch/mvme68k/dev/pccreg.h +++ b/sys/arch/mvme68k/dev/pccreg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pccreg.h,v 1.7 2004/07/30 22:29:45 miod Exp $ */ +/* $OpenBSD: pccreg.h,v 1.8 2012/11/04 13:33:32 miod Exp $ */ /* * Copyright (c) 1995 Theo de Raadt @@ -124,9 +124,12 @@ extern struct pccreg *sys_pcc; #define PCC_TIMERACK 0x80 /* ack intr */ #define PCC_TIMERCLEAR 0x00 /* reset and clear timer */ #define PCC_TIMERSTART 0x03 /* start timer */ +#define PCC_TIMER_COVF 0x04 /* clear overflow */ +#define PCC_TIMER_OVF_SHIFT 4 -#define pcc_timer_hz2lim(hz) (65536 - (160000/(hz))) -#define pcc_timer_us2lim(us) (65536 - (160000/(1000000/(us)))) +#define PCC_TIMERFREQ 160000 /* 1000000 /6.25 */ +#define pcc_timer_hz2lim(hz) (65536 - (PCC_TIMERFREQ/(hz))) +#define pcc_timer_us2lim(us) (65536 - (PCC_TIMERFREQ/(1000000/(us)))) /* * serial control diff --git a/sys/arch/mvme68k/dev/pcctworeg.h b/sys/arch/mvme68k/dev/pcctworeg.h index acf36ee3de0..4e2e36de79d 100644 --- a/sys/arch/mvme68k/dev/pcctworeg.h +++ b/sys/arch/mvme68k/dev/pcctworeg.h @@ -1,4 +1,4 @@ -/* $OpenBSD: pcctworeg.h,v 1.6 2004/07/30 22:29:45 miod Exp $ */ +/* $OpenBSD: pcctworeg.h,v 1.7 2012/11/04 13:33:32 miod Exp $ */ /* * Copyright (c) 1995 Theo de Raadt @@ -113,6 +113,7 @@ extern struct pcctworeg *sys_pcc2; #define PCC2_TCTL_COC 0x02 #define PCC2_TCTL_COVF 0x04 #define PCC2_TCTL_OVF 0xf0 +#define PCC2_TCTL_OVF_SHIFT 4 #define PCC2_GPIO_PLTY 0x80 #define PCC2_GPIO_EL 0x40 diff --git a/sys/arch/mvme68k/dev/wl.c b/sys/arch/mvme68k/dev/wl.c index d335f3bc557..0258ed06c9d 100644 --- a/sys/arch/mvme68k/dev/wl.c +++ b/sys/arch/mvme68k/dev/wl.c @@ -1,4 +1,4 @@ -/* $OpenBSD: wl.c,v 1.23 2010/06/28 14:13:29 deraadt Exp $ */ +/* $OpenBSD: wl.c,v 1.24 2012/11/04 13:33:32 miod Exp $ */ /* * Copyright (c) 1995 Dale Rahn. All rights reserved. @@ -1317,11 +1317,11 @@ long *ptime; u_char *msg; { /* - if (*ptime != time.tv_sec) { + if (*ptime != time_second) { */ { /* - *ptime = time.tv_sec; + *ptime = time_second; */ log(LOG_WARNING, "%s%d[%d]: %s overrun\n", wl_cd.cd_name, 0 /* fix */, channel, msg); |