On SMP kernel,

- use "tick" interrupt for per-CPU statclock.
- disable "counter-timer" #1 interrupt and use it as timecounter.
This commit is contained in:
nakayama 2008-03-14 15:38:36 +00:00
parent f5506ae261
commit 74a205f37a

View File

@ -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 <sys/cdefs.h>
__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 <dev/ebus/ebusvar.h>
/*
* 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);
}