diff --git a/sys/arch/sparc64/sparc64/clock.c b/sys/arch/sparc64/sparc64/clock.c index ae9f7d498562..115247275190 100644 --- a/sys/arch/sparc64/sparc64/clock.c +++ b/sys/arch/sparc64/sparc64/clock.c @@ -1,4 +1,4 @@ -/* $NetBSD: clock.c,v 1.89 2008/03/02 15:28:26 nakayama Exp $ */ +/* $NetBSD: clock.c,v 1.90 2008/03/14 15:38:36 nakayama Exp $ */ /* * Copyright (c) 1992, 1993 @@ -55,7 +55,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.89 2008/03/02 15:28:26 nakayama Exp $"); +__KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.90 2008/03/14 15:38:36 nakayama Exp $"); #include "opt_multiprocessor.h" @@ -96,6 +96,15 @@ __KERNEL_RCSID(0, "$NetBSD: clock.c,v 1.89 2008/03/02 15:28:26 nakayama Exp $"); #include +/* + * Clock assignments: + * + * machine hardclock statclock timecounter + * counter-timer timer#0 timer#1 %tick + * counter-timer + SMP timer#0 %tick/CPU timer#1 or %tick + * no counter-timer %tick - %tick + */ + /* * Statistics clock interval and variance, in usec. Variance must be a * power of two. Since this gives us an even number, not an odd number, @@ -112,7 +121,9 @@ int timerok; int schedintr(void *); static struct intrhand level10 = { .ih_fun = clockintr }; +#ifndef MULTIPROCESSOR static struct intrhand level14 = { .ih_fun = statintr }; +#endif static struct intrhand schedint = { .ih_fun = schedintr }; static int timermatch(struct device *, struct cfdata *, void *); @@ -128,14 +139,14 @@ void stopcounter(struct timer_4u *); int timerblurb = 10; /* Guess a value; used before clock is attached */ -static u_int timer_get_timecount(struct timecounter *); +static u_int tick_get_timecount(struct timecounter *); /* - * define timecounter + * define timecounter "tick-counter" */ -static struct timecounter counter_timecounter = { - timer_get_timecount, /* get_timecount */ +static struct timecounter tick_timecounter = { + tick_get_timecount, /* get_timecount */ 0, /* no poll_pps */ ~0u, /* counter_mask */ 0, /* frequency - set at initialisation */ @@ -146,14 +157,43 @@ static struct timecounter counter_timecounter = { }; /* - * timer_get_timecount provide current counter value + * tick_get_timecount provide current tick counter value */ static u_int -timer_get_timecount(struct timecounter *tc) +tick_get_timecount(struct timecounter *tc) { return cpu_counter(); } +#ifdef MULTIPROCESSOR +static u_int counter_get_timecount(struct timecounter *); + +/* + * define timecounter "counter-timer" + */ + +static struct timecounter counter_timecounter = { + counter_get_timecount, /* get_timecount */ + 0, /* no poll_pps */ + TMR_LIM_MASK, /* counter_mask */ + 1000000, /* frequency */ + "counter-timer", /* name */ + 200, /* quality */ + 0, /* private reference - UNUSED */ + NULL /* next timecounter */ +}; + +/* + * counter_get_timecount provide current counter value + */ +static u_int +counter_get_timecount(struct timecounter *tc) +{ + return (u_int)ldxa((vaddr_t)&timerreg_4u.t_timer[1].t_count, + ASI_NUCLEUS) & TMR_LIM_MASK; +} +#endif + /* * The sun4u OPENPROMs call the timer the "counter-timer", except for * the lame UltraSPARC IIi PCI machines that don't have them. @@ -185,17 +225,31 @@ timerattach(struct device *parent, struct device *self, void *aux) timerreg_4u.t_clrintr = (int64_t *)(u_long)va[1]; timerreg_4u.t_mapintr = (int64_t *)(u_long)va[2]; + /* + * Disable interrupts for now. + * N.B. By default timer[0] is disabled and timer[1] is enabled. + */ + stxa((vaddr_t)&timerreg_4u.t_mapintr[0], ASI_NUCLEUS, + (timerreg_4u.t_mapintr[0] & ~(INTMAP_V|INTMAP_TID)) | + (CPU_UPAID << INTMAP_TID_SHIFT)); + stxa((vaddr_t)&timerreg_4u.t_mapintr[1], ASI_NUCLEUS, + (timerreg_4u.t_mapintr[1] & ~(INTMAP_V|INTMAP_TID)) | + (CPU_UPAID << INTMAP_TID_SHIFT)); + /* Install the appropriate interrupt vector here */ level10.ih_number = ma->ma_interrupts[0]; level10.ih_clr = &timerreg_4u.t_clrintr[0]; intr_establish(10, &level10); + printf(" irq vectors %lx", (u_long)level10.ih_number); +#ifndef MULTIPROCESSOR + /* + * On SMP kernel, don't establish interrupt to use it as timecounter. + */ level14.ih_number = ma->ma_interrupts[1]; level14.ih_clr = &timerreg_4u.t_clrintr[1]; - intr_establish(14, &level14); - printf(" irq vectors %lx and %lx", - (u_long)level10.ih_number, - (u_long)level14.ih_number); + printf(" and %lx", (u_long)level14.ih_number); +#endif #if 0 cnt = &(timerreg_4u.t_timer[0].t_count); @@ -258,21 +312,22 @@ stopcounter(struct timer_4u *creg) * but the shortcut during dispatch makes it work. */ void -tickintr_establish() +tickintr_establish(int pil, int (*fun)(void *)) { + int s; struct intrhand *ih; ih = malloc(sizeof(struct intrhand), M_DEVBUF, M_NOWAIT|M_ZERO); KASSERT(ih != NULL); - ih->ih_fun = tickintr; + ih->ih_fun = fun; ih->ih_arg = 0; ih->ih_clr = 0; ih->ih_number = 1; if (CPU_IS_PRIMARY(curcpu())) - intr_establish(10, ih); + intr_establish(pil, ih); else { - ih->ih_pil = 10; + ih->ih_pil = pil; ih->ih_pending = 0; ih->ih_next = NULL; } @@ -284,7 +339,9 @@ tickintr_establish() printf("Using %%tick -- intr in %ld cycles\n", curcpu()->ci_tick_increment); #endif + s = intr_disable(); next_tick(curcpu()->ci_tick_increment); + intr_restore(s); } /* @@ -336,8 +393,8 @@ cpu_initclocks() } #endif - counter_timecounter.tc_frequency = curcpu()->ci_cpu_clockrate[0]; - tc_init(&counter_timecounter); + tick_timecounter.tc_frequency = curcpu()->ci_cpu_clockrate[0]; + tc_init(&tick_timecounter); /* * Now handle machines w/o counter-timers. @@ -350,7 +407,7 @@ cpu_initclocks() (unsigned long)curcpu()->ci_cpu_clockrate[1]); /* We don't have a counter-timer -- use %tick */ - tickintr_establish(); + tickintr_establish(10, tickintr); /* We only have one timer so we have no statclock */ stathz = 0; @@ -367,7 +424,11 @@ cpu_initclocks() profhz = stathz; /* always */ +#ifdef MULTIPROCESSOR + statint = curcpu()->ci_cpu_clockrate[0] / stathz; +#else statint = 1000000 / stathz; +#endif minint = statint / 2 + 100; while (statvar > minint) statvar >>= 1; @@ -382,16 +443,29 @@ cpu_initclocks() schedhz = stathz/4; /* - * Enable timers - * - * Also need to map the interrupts cause we're not a child of the sbus. - * N.B. By default timer[0] is disabled and timer[1] is enabled. + * Enable counter-timer #0 interrupt for clockintr. */ stxa((vaddr_t)&timerreg_4u.t_timer[0].t_limit, ASI_NUCLEUS, - tmr_ustolim(tick)|TMR_LIM_IEN|TMR_LIM_PERIODIC|TMR_LIM_RELOAD); - stxa((vaddr_t)&timerreg_4u.t_mapintr[0], ASI_NUCLEUS, - timerreg_4u.t_mapintr[0]|INTMAP_V|(CPU_UPAID << INTMAP_TID_SHIFT)); + tmr_ustolim(tick)|TMR_LIM_IEN|TMR_LIM_PERIODIC|TMR_LIM_RELOAD); + stxa((vaddr_t)&timerreg_4u.t_mapintr[0], ASI_NUCLEUS, + timerreg_4u.t_mapintr[0]|INTMAP_V); +#ifdef MULTIPROCESSOR + /* + * Use counter-timer #1 as timecounter. + */ + stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS, + TMR_LIM_MASK); + tc_init(&counter_timecounter); + + /* + * Enable tick interrupt for statintr. + */ + tickintr_establish(14, statintr); +#else + /* + * Enable counter-timer #1 interrupt for statintr. + */ #ifdef DEBUG if (intrdebug) /* Neglect to enable timer */ @@ -403,6 +477,7 @@ cpu_initclocks() tmr_ustolim(statint)|TMR_LIM_IEN|TMR_LIM_RELOAD); stxa((vaddr_t)&timerreg_4u.t_mapintr[1], ASI_NUCLEUS, timerreg_4u.t_mapintr[1]|INTMAP_V|(CPU_UPAID << INTMAP_TID_SHIFT)); +#endif statmin = statint - (statvar >> 1); } @@ -472,10 +547,10 @@ tickintr(void *cap) hardclock((struct clockframe *)cap); - s = splhigh(); + s = intr_disable(); /* Reset the interrupt */ next_tick(curcpu()->ci_tick_increment); - splx(s); + intr_restore(s); curcpu()->ci_tick_evcnt.ev_count++; return (1); @@ -490,6 +565,9 @@ statintr(cap) { register u_long newint, r, var; struct cpu_info *ci = curcpu(); +#ifdef MULTIPROCESSOR + int s; +#endif #ifdef NOT_DEBUG printf("statclock: count %x:%x, limit %x:%x\n", @@ -517,8 +595,15 @@ statintr(cap) if (schedhz) if ((++ci->ci_schedstate.spc_schedticks & 3) == 0) send_softint(-1, PIL_SCHED, &schedint); +#ifdef MULTIPROCESSOR + s = intr_disable(); + next_tick(newint); + intr_restore(s); + curcpu()->ci_tick_evcnt.ev_count++; +#else stxa((vaddr_t)&timerreg_4u.t_timer[1].t_limit, ASI_NUCLEUS, tmr_ustolim(newint)|TMR_LIM_IEN|TMR_LIM_RELOAD); +#endif return (1); }