Index: arch/sparc/conf/GENERIC =================================================================== RCS file: /cvsroot/src/sys/arch/sparc/conf/GENERIC,v retrieving revision 1.256 diff -p -u -r1.256 GENERIC --- arch/sparc/conf/GENERIC 14 Sep 2017 07:58:43 -0000 1.256 +++ arch/sparc/conf/GENERIC 11 Jan 2018 08:18:49 -0000 @@ -125,7 +125,7 @@ options DDB_HISTORY_SIZE=100 # enable h ## Adds code to the kernel that does internal consistency checks, and will ## cause the kernel to panic if corruption of internal data structures ## is detected. -#options DIAGNOSTIC # extra kernel sanity checking +options DIAGNOSTIC # extra kernel sanity checking ## Enable (possibly expensive) debugging code that may also display messages ## on the system console Index: arch/sparc/sparc/timer.c =================================================================== RCS file: /cvsroot/src/sys/arch/sparc/sparc/timer.c,v retrieving revision 1.32 diff -p -u -r1.32 timer.c --- arch/sparc/sparc/timer.c 19 Jan 2014 00:22:33 -0000 1.32 +++ arch/sparc/sparc/timer.c 11 Jan 2018 08:18:49 -0000 @@ -90,20 +90,24 @@ static struct counter { u_int offset; /* accumulated offset due to wraps */ u_int shift; /* scaling for valid bits */ u_int mask; /* valid bit mask */ -} cntr; + __cpu_simple_lock_t lock; /* protects access to offset and reg */ + struct evcnt missed; +} cntr __aligned(CACHE_LINE_SIZE) = { + .missed = EVCNT_INITIALIZER(EVCNT_TYPE_MISC, 0, "counter", "missed"), +}; /* * define timecounter */ static struct timecounter counter_timecounter = { - timer_get_timecount, /* get_timecount */ - 0, /* no poll_pps */ - ~0u, /* counter_mask */ - 0, /* frequency - set at initialisation */ - "timer-counter", /* name */ - 100, /* quality */ - &cntr /* private reference */ + .tc_get_timecount = timer_get_timecount, + .tc_poll_pps = NULL, + .tc_counter_mask = ~0u, + .tc_frequency = 0, + .tc_name = "timer-counter", + .tc_quality = 100, + .tc_priv = &cntr, }; /* @@ -112,29 +116,50 @@ static struct timecounter counter_timeco static u_int timer_get_timecount(struct timecounter *tc) { - struct counter *ctr = (struct counter *)tc->tc_priv; - - u_int c, res, r; + static u_int oldres, oldo; + u_int c, res, r, o; int s; + /* + * We use splhigh/__cpu_simple_lock here as we don't want + * any mutex or lockdebug overhead. + */ s = splhigh(); - - res = c = *ctr->cntreg; + __cpu_simple_lock(&cntr.lock); + res = c = *cntr.cntreg; res &= ~TMR_LIMIT; + o = cntr.offset; + /* + * There are 3 cases here: + * - limit reached, interrupt not yet processed. + * - count reset but offset the same, race between handling + * the interrupt and tickle_tc() updating the offset. + * - normal case. + * + * For the first two cases, add the limit so that we avoid + * time going backwards. + */ if (c != res) { - r = ctr->limit; + r = cntr.limit; + } else if (res < oldres && o == oldo) { + r = cntr.limit; + cntr.missed.ev_count++; } else { r = 0; } - - res >>= ctr->shift; - res &= ctr->mask; - res += r + ctr->offset; + oldres = res; + oldo = o; + __cpu_simple_unlock(&cntr.lock); splx(s); + + res >>= cntr.shift; + res &= cntr.mask; + + res += r + o; return res; } @@ -142,8 +167,15 @@ timer_get_timecount(struct timecounter * void tickle_tc(void) { + if (timecounter->tc_get_timecount == timer_get_timecount) { + int s; + + s = splhigh(); + __cpu_simple_lock(&cntr.lock); cntr.offset += cntr.limit; + __cpu_simple_unlock(&cntr.lock); + splx(s); } } @@ -155,6 +187,8 @@ timerattach(volatile int *cntreg, volati { u_int prec = 0, t0; + evcnt_attach_static(&cntr.missed); + /* * Calibrate delay() by tweaking the magic constant * until a delay(100) actually reads (at least) 100 us on the clock. @@ -190,13 +224,15 @@ timerattach(volatile int *cntreg, volati if ((1 << t0) & prec) break; + __cpu_simple_lock_init(&cntr.lock); + + cntr.offset = 1; cntr.shift = t0; cntr.mask = (1 << (31-t0))-1; counter_timecounter.tc_frequency = 1000000 * (TMR_SHIFT - t0 + 1); printf(": delay constant %d, frequency = %" PRIu64 " Hz\n", timerblurb, counter_timecounter.tc_frequency); -printf("timer: limit %u shift %u mask %x\n", cntr.limit, cntr.shift, cntr.mask); #if defined(SUN4) || defined(SUN4C) if (CPU_ISSUN4 || CPU_ISSUN4C) { @@ -214,6 +250,7 @@ printf("timer: limit %u shift %u mask %x cntr.limit = tmr_ustolim4m(tick); } #endif + /* link interrupt handlers */ intr_establish(10, 0, &level10, NULL, true); intr_establish(14, 0, &level14, NULL, true); Index: arch/sparc/sparc/timer_sun4m.c =================================================================== RCS file: /cvsroot/src/sys/arch/sparc/sparc/timer_sun4m.c,v retrieving revision 1.30 diff -p -u -r1.30 timer_sun4m.c --- arch/sparc/sparc/timer_sun4m.c 19 Jan 2014 00:22:33 -0000 1.30 +++ arch/sparc/sparc/timer_sun4m.c 11 Jan 2018 08:18:49 -0000 @@ -74,7 +74,7 @@ __KERNEL_RCSID(0, "$NetBSD: timer_sun4m. #include #include -struct timer_4m *timerreg4m; +static struct timer_4m *timerreg4m; #define counterreg4m cpuinfo.counterreg_4m /* @@ -160,9 +160,13 @@ clockintr_4m(void *cap) */ if (cold) return 0; + kpreempt_disable(); - /* read the limit register to clear the interrupt */ + + /* Read the limit register to clear the interrupt. */ *((volatile int *)&timerreg4m->t_limit); + + /* Update the timecounter offset. */ tickle_tc(); /* Index: arch/sparc/sparc/timerreg.h =================================================================== RCS file: /cvsroot/src/sys/arch/sparc/sparc/timerreg.h,v retrieving revision 1.9 diff -p -u -r1.9 timerreg.h --- arch/sparc/sparc/timerreg.h 16 Nov 2005 03:00:23 -0000 1.9 +++ arch/sparc/sparc/timerreg.h 11 Jan 2018 08:18:49 -0000 @@ -120,9 +120,12 @@ struct counter_4m { /* counter that int */ #define tmr_ustolim(n) (((n) + 1) << TMR_SHIFT) -/*efine TMR_SHIFT4M 9 -* shift to obtain microseconds */ -/*efine tmr_ustolim4m(n) (((2*(n)) + 1) << TMR_SHIFT4M)*/ +#define TMR_SHIFT4M 9 /* shift to obtain microseconds */ +#if 1 +#define tmr_ustolim4m(n) (((2*(n)) + 1) << TMR_SHIFT4M) +#else #define tmr_ustolim4m(n) ((n) << TMR_SHIFT) +#endif /* The number of microseconds represented by a counter register value */ #define tmr_cnttous(c) ((((c) >> TMR_SHIFT) & TMR_MASK) - 1)