Update MIPS timer code (except RMI) to utilize new MI event timer

infrastructure.

Reviewed by:	neel
This commit is contained in:
Alexander Motin 2010-07-23 07:46:55 +00:00
parent 733a9e2783
commit 44d1534122
6 changed files with 139 additions and 130 deletions

View File

@ -88,6 +88,7 @@ libkern/umoddi3.c optional isa_mips32
#libkern/mips/strcmp.S standard
#libkern/mips/strncmp.S standard
kern/kern_clocksource.c standard
kern/link_elf_obj.c standard
dev/cfe/cfe_api.c optional cfe

View File

@ -27,9 +27,12 @@
#define IPI_STOP 0x0008
#define IPI_STOP_HARD 0x0008
#define IPI_PREEMPT 0x0010
#define IPI_HARDCLOCK 0x0020
#define IPI_STATCLOCK 0x0040
#ifndef LOCORE
void ipi_all_but_self(int ipi);
void ipi_selected(cpumask_t cpus, int ipi);
void smp_init_secondary(u_int32_t cpuid);
void mpentry(void);

View File

@ -307,7 +307,9 @@ mips_proc0_init(void)
void
cpu_initclocks(void)
{
platform_initclocks();
cpu_initclocks_bsp();
}
struct msgbuf *msgbufp=0;

View File

@ -71,6 +71,13 @@ ipi_send(struct pcpu *pc, int ipi)
CTR1(KTR_SMP, "%s: sent", __func__);
}
void
ipi_all_but_self(int ipi)
{
ipi_selected(PCPU_GET(other_cpus), ipi);
}
/* Send an IPI to a set of cpus. */
void
ipi_selected(cpumask_t cpus, int ipi)
@ -146,6 +153,14 @@ mips_ipi_handler(void *arg)
CTR1(KTR_SMP, "%s: IPI_PREEMPT", __func__);
sched_preempt(curthread);
break;
case IPI_HARDCLOCK:
CTR1(KTR_SMP, "%s: IPI_HARDCLOCK", __func__);
hardclockintr(arg);;
break;
case IPI_STATCLOCK:
CTR1(KTR_SMP, "%s: IPI_STATCLOCK", __func__);
statclockintr(arg);;
break;
default:
panic("Unknown IPI 0x%0x on cpu %d", ipi, curcpu);
}
@ -290,13 +305,11 @@ smp_init_secondary(u_int32_t cpuid)
while (smp_started == 0)
; /* nothing */
/*
* Bootstrap the compare register.
*/
mips_wr_compare(mips_rd_count() + counter_freq / hz);
intr_enable();
/* Start per-CPU event timers. */
cpu_initclocks_ap();
/* enter the scheduler */
sched_throw(NULL);

View File

@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$");
#include <sys/power.h>
#include <sys/smp.h>
#include <sys/time.h>
#include <sys/timeet.h>
#include <sys/timetc.h>
#include <machine/hwfunc.h>
@ -56,8 +57,8 @@ uint64_t counter_freq;
struct timecounter *platform_timecounter;
static uint64_t cycles_per_tick;
static uint64_t cycles_per_usec;
static DPCPU_DEFINE(uint32_t, cycles_per_tick);
static uint32_t cycles_per_usec;
static u_int32_t counter_upper = 0;
static u_int32_t counter_lower_last = 0;
@ -65,6 +66,15 @@ static u_int32_t counter_lower_last = 0;
static DPCPU_DEFINE(uint32_t, compare_ticks);
static DPCPU_DEFINE(uint32_t, lost_ticks);
struct clock_softc {
int intr_rid;
struct resource *intr_res;
void *intr_handler;
struct timecounter tc;
struct eventtimer et;
};
static struct clock_softc *softc;
/*
* Device methods
*/
@ -73,15 +83,6 @@ static void clock_identify(driver_t *, device_t);
static int clock_attach(device_t);
static unsigned counter_get_timecount(struct timecounter *tc);
static struct timecounter counter_timecounter = {
counter_get_timecount, /* get_timecount */
0, /* no poll_pps */
0xffffffffu, /* counter_mask */
0, /* frequency */
"MIPS32", /* name */
800, /* quality (adjusted in code) */
};
void
mips_timer_early_init(uint64_t clock_hz)
{
@ -94,8 +95,6 @@ void
platform_initclocks(void)
{
tc_init(&counter_timecounter);
if (platform_timecounter != NULL)
tc_init(platform_timecounter);
}
@ -140,40 +139,7 @@ mips_timer_init_params(uint64_t platform_counter_freq, int double_count)
if (double_count != 0)
counter_freq /= 2;
/*
* We want to run stathz in the neighborhood of 128hz. We would
* like profhz to run as often as possible, so we let it run on
* each clock tick. We try to honor the requested 'hz' value as
* much as possible.
*
* If 'hz' is above 1500, then we just let the timer
* (and profhz) run at hz. If 'hz' is below 1500 but above
* 750, then we let the timer run at 2 * 'hz'. If 'hz'
* is below 750 then we let the timer run at 4 * 'hz'.
*/
if (hz >= 1500)
timer1hz = hz;
else if (hz >= 750)
timer1hz = hz * 2;
else
timer1hz = hz * 4;
if (timer1hz < 128)
stathz = timer1hz;
else
stathz = timer1hz / (timer1hz / 128);
profhz = timer1hz;
cycles_per_tick = counter_freq / timer1hz;
cycles_per_usec = counter_freq / (1 * 1000 * 1000);
counter_timecounter.tc_frequency = counter_freq;
printf("hz=%d timer1hz:%d cyl_per_tick:%jd cyl_per_usec:%jd freq:%jd\n",
hz,
timer1hz,
cycles_per_tick,
cycles_per_usec,
counter_freq);
set_cputicker(tick_ticker, counter_freq, 1);
}
@ -183,13 +149,14 @@ sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS)
int error;
uint64_t freq;
if (counter_timecounter.tc_frequency == 0)
if (softc == NULL)
return (EOPNOTSUPP);
freq = counter_freq;
error = sysctl_handle_int(oidp, &freq, sizeof(freq), req);
if (error == 0 && req->newptr != NULL) {
counter_freq = freq;
counter_timecounter.tc_frequency = counter_freq;
softc->et.et_frequency = counter_freq;
softc->tc.tc_frequency = counter_freq;
}
return (error);
}
@ -205,19 +172,6 @@ counter_get_timecount(struct timecounter *tc)
return (mips_rd_count());
}
void
cpu_startprofclock(void)
{
/* nothing to do */
}
void
cpu_stopprofclock(void)
{
/* nothing to do */
}
/*
* Wait for about n microseconds (at least!).
*/
@ -251,23 +205,62 @@ DELAY(int n)
}
}
static int
clock_start(struct eventtimer *et,
struct bintime *first, struct bintime *period)
{
uint32_t fdiv, div, next;
if (period != NULL) {
div = (et->et_frequency * (period->frac >> 32)) >> 32;
if (period->sec != 0)
div += et->et_frequency * period->sec;
} else
div = 0;
if (first != NULL) {
fdiv = (et->et_frequency * (first->frac >> 32)) >> 32;
if (first->sec != 0)
fdiv += et->et_frequency * first->sec;
} else
fdiv = div;
DPCPU_SET(cycles_per_tick, div);
next = mips_rd_count() + fdiv;
DPCPU_SET(compare_ticks, next);
mips_wr_compare(next);
return (0);
}
static int
clock_stop(struct eventtimer *et)
{
DPCPU_SET(cycles_per_tick, 0);
mips_wr_compare(0xffffffff);
return (0);
}
/*
* Device section of file below
*/
static int
clock_intr(void *arg)
{
struct trapframe *tf;
struct clock_softc *sc = (struct clock_softc *)arg;
uint32_t cycles_per_tick;
uint32_t count, compare_last, compare_next, lost_ticks;
cycles_per_tick = DPCPU_GET(cycles_per_tick);
/*
* Set next clock edge.
*/
count = mips_rd_count();
compare_last = DPCPU_GET(compare_ticks);
compare_next = count + cycles_per_tick;
DPCPU_SET(compare_ticks, compare_next);
mips_wr_compare(compare_next);
if (cycles_per_tick > 0) {
compare_next = count + cycles_per_tick;
DPCPU_SET(compare_ticks, compare_next);
mips_wr_compare(compare_next);
} else
mips_wr_compare(0xffffffff);
critical_enter();
if (count < counter_lower_last) {
@ -275,45 +268,34 @@ clock_intr(void *arg)
counter_lower_last = count;
}
/*
* Magic. Setting up with an arg of NULL means we get passed tf.
*/
tf = (struct trapframe *)arg;
if (cycles_per_tick > 0) {
/*
* Account for the "lost time" between when the timer interrupt fired
* and when 'clock_intr' actually started executing.
*/
lost_ticks = DPCPU_GET(lost_ticks);
lost_ticks += count - compare_last;
/*
* Account for the "lost time" between when the timer interrupt
* fired and when 'clock_intr' actually started executing.
*/
lost_ticks = DPCPU_GET(lost_ticks);
lost_ticks += count - compare_last;
/*
* If the COUNT and COMPARE registers are no longer in sync
* then make up some reasonable value for the 'lost_ticks'.
*
* This could happen, for e.g., after we resume normal
* operations after exiting the debugger.
*/
if (lost_ticks > 2 * cycles_per_tick)
lost_ticks = cycles_per_tick;
/*
* If the COUNT and COMPARE registers are no longer in sync then make
* up some reasonable value for the 'lost_ticks'.
*
* This could happen, for e.g., after we resume normal operations after
* exiting the debugger.
*/
if (lost_ticks > 2 * cycles_per_tick)
lost_ticks = cycles_per_tick;
while (lost_ticks >= cycles_per_tick) {
timer1clock(TRAPF_USERMODE(tf), tf->pc);
lost_ticks -= cycles_per_tick;
while (lost_ticks >= cycles_per_tick) {
if (sc->et.et_active)
sc->et.et_event_cb(&sc->et, sc->et.et_arg);
lost_ticks -= cycles_per_tick;
}
DPCPU_SET(lost_ticks, lost_ticks);
}
DPCPU_SET(lost_ticks, lost_ticks);
#ifdef KDTRACE_HOOKS
/*
* If the DTrace hooks are configured and a callback function
* has been registered, then call it to process the high speed
* timers.
*/
int cpu = PCPU_GET(cpuid);
if (cyclic_clock_func[cpu] != NULL)
(*cyclic_clock_func[cpu])(tf);
#endif
timer1clock(TRAPF_USERMODE(tf), tf->pc);
if (sc->et.et_active)
sc->et.et_event_cb(&sc->et, sc->et.et_arg);
critical_exit();
return (FILTER_HANDLED);
}
@ -339,25 +321,45 @@ clock_identify(driver_t * drv, device_t parent)
static int
clock_attach(device_t dev)
{
struct resource *irq;
struct clock_softc *sc;
int error;
int rid;
rid = 0;
irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 5, 5, 1, RF_ACTIVE);
if (irq == NULL) {
softc = sc = device_get_softc(dev);
sc->intr_rid = 0;
sc->intr_res = bus_alloc_resource(dev,
SYS_RES_IRQ, &sc->intr_rid, 5, 5, 1, RF_ACTIVE);
if (sc->intr_res == NULL) {
device_printf(dev, "failed to allocate irq\n");
return (ENXIO);
}
error = bus_setup_intr(dev, irq, INTR_TYPE_CLK, clock_intr, NULL,
NULL, NULL);
error = bus_setup_intr(dev, sc->intr_res, INTR_TYPE_CLK,
clock_intr, NULL, sc, &sc->intr_handler);
if (error != 0) {
device_printf(dev, "bus_setup_intr returned %d\n", error);
return (error);
}
mips_wr_compare(mips_rd_count() + counter_freq / hz);
sc->tc.tc_get_timecount = counter_get_timecount;
sc->tc.tc_counter_mask = 0xffffffff;
sc->tc.tc_frequency = counter_freq;
sc->tc.tc_name = "MIPS32";
sc->tc.tc_quality = 800;
sc->tc.tc_priv = sc;
tc_init(&sc->tc);
sc->et.et_name = "MIPS32";
sc->et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
ET_FLAGS_PERCPU;
sc->et.et_quality = 800;
sc->et.et_frequency = counter_freq;
sc->et.et_min_period.sec = 0;
sc->et.et_min_period.frac = 0x00004000LLU << 32;
sc->et.et_max_period.sec = 0xfffffffeU / sc->et.et_frequency;
sc->et.et_max_period.frac =
((0xfffffffeLLU << 32) / sc->et.et_frequency) << 32;
sc->et.et_start = clock_start;
sc->et.et_stop = clock_stop;
sc->et.et_priv = sc;
et_register(&sc->et);
return (0);
}
@ -373,7 +375,9 @@ static device_method_t clock_methods[] = {
};
static driver_t clock_driver = {
"clock", clock_methods, 32
"clock",
clock_methods,
sizeof(struct clock_softc),
};
static devclass_t clock_devclass;

View File

@ -72,20 +72,6 @@ tick_init(void)
tc_init(&counter_timecounter);
}
void
cpu_startprofclock(void)
{
/* nothing to do */
}
void
cpu_stopprofclock(void)
{
/* nothing to do */
}
static int
sysctl_machdep_counter_freq(SYSCTL_HANDLER_ARGS)
{