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:
parent
f5506ae261
commit
74a205f37a
@ -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);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user