diff --git a/sys/arch/acorn26/include/types.h b/sys/arch/acorn26/include/types.h index 62ebaf106c54..4093977f4c40 100644 --- a/sys/arch/acorn26/include/types.h +++ b/sys/arch/acorn26/include/types.h @@ -1,4 +1,4 @@ -/* $NetBSD: types.h,v 1.7 2006/09/03 11:51:29 bjh21 Exp $ */ +/* $NetBSD: types.h,v 1.8 2006/10/04 23:40:00 bjh21 Exp $ */ #ifndef _ACORN26_TYPES_H_ #define _ACORN26_TYPES_H_ @@ -8,5 +8,6 @@ #define __HAVE_GENERIC_SOFT_INTERRUPTS #define __GENERIC_SOFT_INTERRUPTS_ALL_LEVELS #define __HAVE_GENERIC_TODR +#define __HAVE_TIMECOUNTER #endif /* _ACORN26_TYPES_H_ */ diff --git a/sys/arch/acorn26/iobus/ioc.c b/sys/arch/acorn26/iobus/ioc.c index e2421ff881b1..559db5d51f53 100644 --- a/sys/arch/acorn26/iobus/ioc.c +++ b/sys/arch/acorn26/iobus/ioc.c @@ -1,4 +1,4 @@ -/* $NetBSD: ioc.c,v 1.14 2006/10/04 20:29:51 bjh21 Exp $ */ +/* $NetBSD: ioc.c,v 1.15 2006/10/04 23:40:00 bjh21 Exp $ */ /*- * Copyright (c) 1998, 1999, 2000 Ben Harris @@ -31,7 +31,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: ioc.c,v 1.14 2006/10/04 20:29:51 bjh21 Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ioc.c,v 1.15 2006/10/04 23:40:00 bjh21 Exp $"); #include #include @@ -39,6 +39,7 @@ __KERNEL_RCSID(0, "$NetBSD: ioc.c,v 1.14 2006/10/04 20:29:51 bjh21 Exp $"); #include #include /* For bootverbose */ #include +#include #include #include @@ -58,6 +59,7 @@ static int ioc_search(struct device *parent, struct cfdata *cf, static int ioc_print(void *aux, const char *pnp); static int ioc_irq_clock(void *cookie); static int ioc_irq_statclock(void *cookie); +static u_int ioc_get_timecount(struct timecounter *); CFATTACH_DECL(ioc, sizeof(struct ioc_softc), ioc_match, ioc_attach, NULL, NULL); @@ -333,6 +335,13 @@ cpu_initclocks(void) sc->sc_dev.dv_xname, "clock"); sc->sc_clkirq = irq_establish(IOC_IRQ_TM0, IPL_CLOCK, ioc_irq_clock, NULL, &sc->sc_clkev); + sc->sc_tc.tc_get_timecount = ioc_get_timecount; + sc->sc_tc.tc_counter_mask = ~(u_int)0; + sc->sc_tc.tc_frequency = IOC_TIMER_RATE; + sc->sc_tc.tc_name = sc->sc_dev.dv_xname; + sc->sc_tc.tc_quality = 100; + sc->sc_tc.tc_priv = sc; + tc_init(&sc->sc_tc); if (bootverbose) printf("%s: %d Hz clock interrupting at %s\n", the_ioc->dv_xname, hz, irq_string(sc->sc_clkirq)); @@ -365,7 +374,9 @@ cpu_initclocks(void) static int ioc_irq_clock(void *cookie) { + struct ioc_softc *sc = (void *)the_ioc; + sc->sc_tcbase += t0_count + 1; hardclock(cookie); return IRQ_HANDLED; } @@ -403,82 +414,40 @@ setstatclockrate(int hzrate) KASSERT(hzrate == stathz); } -void -microtime(struct timeval *tvp) +/* + * IOC timecounter + * + * We construct a timecounter from timer 0, which is also running the + * hardclock interrupt. Since the timer 0 resets on every hardclock + * interrupt, we keep track of the high-order bits of the counter in + * software, incrementing it on every hardclock. If hardclock + * interrupts are disabled, there's a period where the timer has reset + * but the interrupt handler hasn't incremented the hight-order bits. + * We detect this by checking whether there's a hardclock interrupt + * pending. We take a bit of extra care to ensure that we aren't + * confused by the interrupt happening between our latching the + * timer's count and reading the interrupt flag. + */ +static u_int +ioc_get_timecount(struct timecounter *tc) { - static struct timeval lasttime; - struct timeval t; - struct device *self; - struct ioc_softc *sc; - bus_space_tag_t bst; - bus_space_handle_t bsh; - long sec, usec; - int t0, s, intbefore, intafter; - - KASSERT(the_ioc != NULL); - self = the_ioc; - sc = (struct ioc_softc *)self; - - bst = sc->sc_bst; - bsh = sc->sc_bsh; + struct ioc_softc *sc = tc->tc_priv; + bus_space_tag_t bst = sc->sc_bst; + bus_space_handle_t bsh = sc->sc_bsh; + u_int t0, count; + int s, intpending; s = splclock(); - - t = time; - - intbefore = ioc_irq_status(IOC_IRQ_TM0); bus_space_write_1(bst, bsh, IOC_T0LATCH, 0); + if (__predict_false((intpending = ioc_irq_status(IOC_IRQ_TM0)))) + bus_space_write_1(bst, bsh, IOC_T0LATCH, 0); t0 = bus_space_read_1(bst, bsh, IOC_T0LOW); t0 += bus_space_read_1(bst, bsh, IOC_T0HIGH) << 8; - intafter = ioc_irq_status(IOC_IRQ_TM0); - + count = sc->sc_tcbase - t0; + if (intpending) + count += t0_count + 1; splx(s); - - /* - * If there's a timer interrupt pending, the counter has - * probably wrapped around once since "time" was last updated. - * Things are complicated by the fact that this could happen - * while we're trying to work out the time. We include some - * heuristics to spot this. - * - * NB: t0 counts down from t0_count to 0. - */ - - if (intbefore || (intafter && t0 < t0_count / 2)) - t0 -= t0_count; - - t.tv_usec += (t0_count - t0) / (IOC_TIMER_RATE / 1000000); - - while (t.tv_usec > 1000000) { - t.tv_usec -= 1000000; - t.tv_sec++; - } - - /* - * Ordinarily, the current clock time is guaranteed to be later - * by at least one microsecond than the last time the clock was - * read. However, this rule applies only if the current time is - * within one second of the last time. Otherwise, the clock will - * (shudder) be set backward. The clock adjustment daemon or - * human equivalent is presumed to be correctly implemented and - * to set the clock backward only upon unavoidable crisis. - */ - sec = lasttime.tv_sec - t.tv_sec; - usec = lasttime.tv_usec - t.tv_usec; - if (usec < 0) { - usec += 1000000; - sec--; - } - if (sec == 0) { - t.tv_usec += usec + 1; - if (t.tv_usec >= 1000000) { - t.tv_usec -= 1000000; - t.tv_sec++; - } - } - lasttime = t; - - *tvp = t; + return count; } void diff --git a/sys/arch/acorn26/iobus/iocvar.h b/sys/arch/acorn26/iobus/iocvar.h index cec4e3b7187a..3bdf604a0151 100644 --- a/sys/arch/acorn26/iobus/iocvar.h +++ b/sys/arch/acorn26/iobus/iocvar.h @@ -1,4 +1,4 @@ -/* $NetBSD: iocvar.h,v 1.3 2006/09/30 15:14:21 bjh21 Exp $ */ +/* $NetBSD: iocvar.h,v 1.4 2006/10/04 23:40:00 bjh21 Exp $ */ /*- * Copyright (c) 1998, 1999 Ben Harris * All rights reserved. @@ -32,6 +32,7 @@ #ifndef _ARM26_IOCVAR_H #define _ARM26_IOCVAR_H +#include #include /* Structure passed to children of an IOC */ @@ -58,6 +59,8 @@ struct ioc_softc { struct evcnt sc_clkev; struct irq_handler *sc_sclkirq; struct evcnt sc_sclkev; + struct timecounter sc_tc; + u_int sc_tcbase; u_int8_t sc_ctl; };