summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--sys/conf/files.mips1
-rw-r--r--sys/mips/include/smp.h3
-rw-r--r--sys/mips/mips/machdep.c2
-rw-r--r--sys/mips/mips/mp_machdep.c23
-rw-r--r--sys/mips/mips/tick.c228
-rw-r--r--sys/mips/rmi/tick.c14
6 files changed, 140 insertions, 131 deletions
diff --git a/sys/conf/files.mips b/sys/conf/files.mips
index 0bec97b..c33fa9a 100644
--- a/sys/conf/files.mips
+++ b/sys/conf/files.mips
@@ -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
diff --git a/sys/mips/include/smp.h b/sys/mips/include/smp.h
index 216b9e7..cf2261c 100644
--- a/sys/mips/include/smp.h
+++ b/sys/mips/include/smp.h
@@ -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);
diff --git a/sys/mips/mips/machdep.c b/sys/mips/mips/machdep.c
index eede505..060e101 100644
--- a/sys/mips/mips/machdep.c
+++ b/sys/mips/mips/machdep.c
@@ -307,7 +307,9 @@ mips_proc0_init(void)
void
cpu_initclocks(void)
{
+
platform_initclocks();
+ cpu_initclocks_bsp();
}
struct msgbuf *msgbufp=0;
diff --git a/sys/mips/mips/mp_machdep.c b/sys/mips/mips/mp_machdep.c
index 00a91fb..5764326 100644
--- a/sys/mips/mips/mp_machdep.c
+++ b/sys/mips/mips/mp_machdep.c
@@ -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);
diff --git a/sys/mips/mips/tick.c b/sys/mips/mips/tick.c
index 5432c42..06c9aa7 100644
--- a/sys/mips/mips/tick.c
+++ b/sys/mips/mips/tick.c
@@ -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;
-
- /*
- * 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;
+ /*
+ * 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;
+
+ 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;
diff --git a/sys/mips/rmi/tick.c b/sys/mips/rmi/tick.c
index aaeb0e9..08dc4ad 100644
--- a/sys/mips/rmi/tick.c
+++ b/sys/mips/rmi/tick.c
@@ -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)
{
OpenPOWER on IntegriCloud