summaryrefslogtreecommitdiffstats
path: root/sys/sparc64
diff options
context:
space:
mode:
authormav <mav@FreeBSD.org>2010-07-29 12:08:46 +0000
committermav <mav@FreeBSD.org>2010-07-29 12:08:46 +0000
commit4f9a242ba1a525c2a24372820745ea1ac3b32a22 (patch)
tree1baf2b9638c10821a6a2d8440f3504707e019edf /sys/sparc64
parent9ce81bb370e2f2664e14369a49ab80d2d2ab3a4c (diff)
downloadFreeBSD-src-4f9a242ba1a525c2a24372820745ea1ac3b32a22.zip
FreeBSD-src-4f9a242ba1a525c2a24372820745ea1ac3b32a22.tar.gz
Adapt sparc64 and sun4v timer code for the new event timers infrastructure.
Reviewed by: marius@
Diffstat (limited to 'sys/sparc64')
-rw-r--r--sys/sparc64/include/intr_machdep.h2
-rw-r--r--sys/sparc64/include/pcpu.h1
-rw-r--r--sys/sparc64/include/smp.h2
-rw-r--r--sys/sparc64/include/tick.h1
-rw-r--r--sys/sparc64/sparc64/clock.c11
-rw-r--r--sys/sparc64/sparc64/intr_machdep.c4
-rw-r--r--sys/sparc64/sparc64/mp_machdep.c24
-rw-r--r--sys/sparc64/sparc64/tick.c171
8 files changed, 152 insertions, 64 deletions
diff --git a/sys/sparc64/include/intr_machdep.h b/sys/sparc64/include/intr_machdep.h
index e3667e1..254ac78 100644
--- a/sys/sparc64/include/intr_machdep.h
+++ b/sys/sparc64/include/intr_machdep.h
@@ -46,6 +46,8 @@
#define PIL_AST 4 /* ast ipi */
#define PIL_STOP 5 /* stop cpu ipi */
#define PIL_PREEMPT 6 /* preempt idle thread cpu ipi */
+#define PIL_HARDCLOCK 7 /* hardclock broadcast */
+#define PIL_STATCLOCK 8 /* statclock broadcast */
#define PIL_FILTER 12 /* filter interrupts */
#define PIL_FAST 13 /* fast interrupts */
#define PIL_TICK 14 /* tick interrupts */
diff --git a/sys/sparc64/include/pcpu.h b/sys/sparc64/include/pcpu.h
index f5735bf..24548d0 100644
--- a/sys/sparc64/include/pcpu.h
+++ b/sys/sparc64/include/pcpu.h
@@ -53,6 +53,7 @@ struct pmap;
vm_offset_t pc_addr; \
u_long pc_tickref; \
u_long pc_tickadj; \
+ u_long pc_tickincrement; \
u_int pc_clock; \
u_int pc_impl; \
u_int pc_mid; \
diff --git a/sys/sparc64/include/smp.h b/sys/sparc64/include/smp.h
index eda6d6f..a0e14c9 100644
--- a/sys/sparc64/include/smp.h
+++ b/sys/sparc64/include/smp.h
@@ -58,6 +58,8 @@
#define IPI_AST PIL_AST
#define IPI_RENDEZVOUS PIL_RENDEZVOUS
#define IPI_PREEMPT PIL_PREEMPT
+#define IPI_HARDCLOCK PIL_HARDCLOCK
+#define IPI_STATCLOCK PIL_STATCLOCK
#define IPI_STOP PIL_STOP
#define IPI_STOP_HARD PIL_STOP
diff --git a/sys/sparc64/include/tick.h b/sys/sparc64/include/tick.h
index ae80d53..979e93f 100644
--- a/sys/sparc64/include/tick.h
+++ b/sys/sparc64/include/tick.h
@@ -32,7 +32,6 @@
extern u_int hardclock_use_stick;
void tick_clear(u_int cpu_impl);
-void tick_start(void);
void tick_stop(u_int cpu_impl);
#endif
diff --git a/sys/sparc64/sparc64/clock.c b/sys/sparc64/sparc64/clock.c
index abf3274..e618f5d 100644
--- a/sys/sparc64/sparc64/clock.c
+++ b/sys/sparc64/sparc64/clock.c
@@ -81,14 +81,3 @@ delay_tick(int usec)
sched_unpin();
}
-void
-cpu_startprofclock(void)
-{
-
-}
-
-void
-cpu_stopprofclock(void)
-{
-
-}
diff --git a/sys/sparc64/sparc64/intr_machdep.c b/sys/sparc64/sparc64/intr_machdep.c
index 7a73bbc..8e610f6 100644
--- a/sys/sparc64/sparc64/intr_machdep.c
+++ b/sys/sparc64/sparc64/intr_machdep.c
@@ -96,7 +96,9 @@ static const char *const pil_names[] = {
"ast", /* PIL_AST */
"stop", /* PIL_STOP */
"preempt", /* PIL_PREEMPT */
- "stray", "stray", "stray", "stray", "stray",
+ "hardclock", /* PIL_HARDCLOCK */
+ "statclock", /* PIL_STATCLOCK */
+ "stray", "stray", "stray",
"filter", /* PIL_FILTER */
"fast", /* PIL_FAST */
"tick", /* PIL_TICK */
diff --git a/sys/sparc64/sparc64/mp_machdep.c b/sys/sparc64/sparc64/mp_machdep.c
index 4281204..549b3d2 100644
--- a/sys/sparc64/sparc64/mp_machdep.c
+++ b/sys/sparc64/sparc64/mp_machdep.c
@@ -96,7 +96,9 @@ __FBSDID("$FreeBSD$");
#define SUNW_STOPSELF "SUNW,stop-self"
static ih_func_t cpu_ipi_ast;
+static ih_func_t cpu_ipi_hardclock;
static ih_func_t cpu_ipi_preempt;
+static ih_func_t cpu_ipi_statclock;
static ih_func_t cpu_ipi_stop;
/*
@@ -279,6 +281,8 @@ cpu_mp_start(void)
-1, NULL, NULL);
intr_setup(PIL_STOP, cpu_ipi_stop, -1, NULL, NULL);
intr_setup(PIL_PREEMPT, cpu_ipi_preempt, -1, NULL, NULL);
+ intr_setup(PIL_HARDCLOCK, cpu_ipi_hardclock, -1, NULL, NULL);
+ intr_setup(PIL_STATCLOCK, cpu_ipi_statclock, -1, NULL, NULL);
cpuid_to_mid[curcpu] = PCPU_GET(mid);
@@ -437,9 +441,6 @@ cpu_mp_bootstrap(struct pcpu *pc)
wrpr(pil, 0, PIL_TICK);
wrpr(pstate, 0, PSTATE_KERNEL);
- /* Start the (S)TICK interrupts. */
- tick_start();
-
smp_cpus++;
KASSERT(curthread != NULL, ("%s: curthread", __func__));
PCPU_SET(other_cpus, all_cpus & ~(1 << curcpu));
@@ -451,6 +452,9 @@ cpu_mp_bootstrap(struct pcpu *pc)
while (csa->csa_count != 0)
;
+ /* Start per-CPU event timers. */
+ cpu_initclocks_ap();
+
/* Ok, now enter the scheduler. */
sched_throw(NULL);
}
@@ -508,6 +512,20 @@ cpu_ipi_preempt(struct trapframe *tf)
}
static void
+cpu_ipi_hardclock(struct trapframe *tf)
+{
+
+ hardclockintr(tf);
+}
+
+static void
+cpu_ipi_statclock(struct trapframe *tf)
+{
+
+ statclockintr(tf);
+}
+
+static void
spitfire_ipi_selected(u_int cpus, u_long d0, u_long d1, u_long d2)
{
u_int cpu;
diff --git a/sys/sparc64/sparc64/tick.c b/sys/sparc64/sparc64/tick.c
index 041faa0..f317981 100644
--- a/sys/sparc64/sparc64/tick.c
+++ b/sys/sparc64/sparc64/tick.c
@@ -38,6 +38,7 @@ __FBSDID("$FreeBSD$");
#include <sys/sched.h>
#include <sys/smp.h>
#include <sys/sysctl.h>
+#include <sys/timeet.h>
#include <sys/timetc.h>
#include <dev/ofw/openfirm.h>
@@ -48,9 +49,7 @@ __FBSDID("$FreeBSD$");
#include <machine/tick.h>
#include <machine/ver.h>
-/* 10000 ticks proved okay for 500MHz. */
-#define TICK_GRACE(clock) ((clock) / 1000000 * 2 * 10)
-
+#define STICK_QUALITY -500
#define TICK_QUALITY_MP 10
#define TICK_QUALITY_UP 1000
@@ -76,20 +75,25 @@ u_int hardclock_use_stick = 0;
SYSCTL_INT(_machdep_tick, OID_AUTO, hardclock_use_stick, CTLFLAG_RD,
&hardclock_use_stick, 0, "hardclock uses STICK instead of TICK timer");
+static struct timecounter stick_tc;
static struct timecounter tick_tc;
-static u_long tick_increment;
+static struct eventtimer tick_et;
static uint64_t tick_cputicks(void);
+static timecounter_get_t stick_get_timecount;
static timecounter_get_t tick_get_timecount_up;
#ifdef SMP
static timecounter_get_t tick_get_timecount_mp;
#endif
-static void tick_hardclock(struct trapframe *tf);
-static void tick_hardclock_bbwar(struct trapframe *tf);
+static int tick_et_start(struct eventtimer *et,
+ struct bintime *first, struct bintime *period);
+static int tick_et_stop(struct eventtimer *et);
+static void tick_intr(struct trapframe *tf);
+static void tick_intr_bbwar(struct trapframe *tf);
static inline void tick_hardclock_common(struct trapframe *tf, u_long tick,
u_long adj);
static inline void tick_process(struct trapframe *tf);
-static void stick_hardclock(struct trapframe *tf);
+static void stick_intr(struct trapframe *tf);
static uint64_t
tick_cputicks(void)
@@ -101,39 +105,34 @@ tick_cputicks(void)
void
cpu_initclocks(void)
{
- uint32_t clock;
-
- stathz = hz;
+ uint32_t clock, sclock;
+ clock = PCPU_GET(clock);
+ sclock = 0;
+ if (PCPU_GET(impl) == CPU_IMPL_SPARC64V ||
+ PCPU_GET(impl) >= CPU_IMPL_ULTRASPARCIII) {
+ if (OF_getprop(OF_parent(PCPU_GET(node)), "stick-frequency",
+ &sclock, sizeof(sclock)) == -1) {
+ panic("%s: could not determine STICK frequency",
+ __func__);
+ }
+ }
/*
* Given that the STICK timers typically are driven at rather low
* frequencies they shouldn't be used except when really necessary.
*/
if (hardclock_use_stick != 0) {
- if (OF_getprop(OF_parent(PCPU_GET(node)), "stick-frequency",
- &clock, sizeof(clock)) == -1)
- panic("%s: could not determine STICK frequency", __func__);
- intr_setup(PIL_TICK, stick_hardclock, -1, NULL, NULL);
+ intr_setup(PIL_TICK, stick_intr, -1, NULL, NULL);
/*
* We don't provide a CPU ticker as long as the frequency
* supplied isn't actually used per-CPU.
*/
} else {
- clock = PCPU_GET(clock);
intr_setup(PIL_TICK, PCPU_GET(impl) >= CPU_IMPL_ULTRASPARCI &&
PCPU_GET(impl) < CPU_IMPL_ULTRASPARCIII ?
- tick_hardclock_bbwar : tick_hardclock, -1, NULL, NULL);
+ tick_intr_bbwar : tick_intr, -1, NULL, NULL);
set_cputicker(tick_cputicks, clock, 0);
}
- tick_increment = clock / hz;
- /*
- * Avoid stopping of hardclock in terms of a lost (S)TICK interrupt
- * by ensuring that the (S)TICK period is at least TICK_GRACE ticks.
- */
- if (tick_increment < TICK_GRACE(clock))
- panic("%s: HZ too high, decrease to at least %d",
- __func__, clock / TICK_GRACE(clock));
- tick_start();
/*
* Initialize the TICK-based timecounter. This must not happen
@@ -142,7 +141,7 @@ cpu_initclocks(void)
tick_tc.tc_get_timecount = tick_get_timecount_up;
tick_tc.tc_poll_pps = NULL;
tick_tc.tc_counter_mask = ~0u;
- tick_tc.tc_frequency = PCPU_GET(clock);
+ tick_tc.tc_frequency = clock;
tick_tc.tc_name = "tick";
tick_tc.tc_quality = TICK_QUALITY_UP;
tick_tc.tc_priv = NULL;
@@ -161,19 +160,46 @@ cpu_initclocks(void)
}
#endif
tc_init(&tick_tc);
+ if (sclock != 0) {
+ stick_tc.tc_get_timecount = stick_get_timecount;
+ stick_tc.tc_poll_pps = NULL;
+ stick_tc.tc_counter_mask = ~0u;
+ stick_tc.tc_frequency = sclock;
+ stick_tc.tc_name = "stick";
+ stick_tc.tc_quality = STICK_QUALITY;
+ stick_tc.tc_priv = NULL;
+ tc_init(&stick_tc);
+ }
+ tick_et.et_name = hardclock_use_stick ? "stick" : "tick";
+ tick_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
+ ET_FLAGS_PERCPU;
+ tick_et.et_quality = 1000;
+ tick_et.et_frequency = hardclock_use_stick ? sclock : clock;
+ tick_et.et_min_period.sec = 0;
+ tick_et.et_min_period.frac = 0x00010000LLU << 32; /* To be safe. */
+ tick_et.et_max_period.sec = 3600 * 24; /* No practical limit. */
+ tick_et.et_max_period.frac = 0;
+ tick_et.et_start = tick_et_start;
+ tick_et.et_stop = tick_et_stop;
+ tick_et.et_priv = NULL;
+ et_register(&tick_et);
+
+ cpu_initclocks_bsp();
}
static inline void
tick_process(struct trapframe *tf)
{
+ struct trapframe *oldframe;
+ struct thread *td;
- if (curcpu == 0)
- hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
- else
- hardclock_cpu(TRAPF_USERMODE(tf));
- if (profprocs != 0)
- profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
- statclock(TRAPF_USERMODE(tf));
+ if (tick_et.et_active) {
+ td = curthread;
+ oldframe = td->td_intr_frame;
+ td->td_intr_frame = tf;
+ tick_et.et_event_cb(&tick_et, tick_et.et_arg);
+ td->td_intr_frame = oldframe;
+ }
}
/*
@@ -184,48 +210,60 @@ tick_process(struct trapframe *tf)
*/
static void
-tick_hardclock(struct trapframe *tf)
+tick_intr(struct trapframe *tf)
{
- u_long adj, tick;
+ u_long adj, tick, tick_increment;
register_t s;
critical_enter();
adj = PCPU_GET(tickadj);
+ tick_increment = PCPU_GET(tickincrement);
s = intr_disable();
tick = rd(tick);
- wr(tick_cmpr, tick + tick_increment - adj, 0);
+ if (tick_increment != 0)
+ wr(tick_cmpr, tick + tick_increment - adj, 0);
+ else
+ wr(tick_cmpr, 1L << 63, 0);
intr_restore(s);
tick_hardclock_common(tf, tick, adj);
critical_exit();
}
static void
-tick_hardclock_bbwar(struct trapframe *tf)
+tick_intr_bbwar(struct trapframe *tf)
{
- u_long adj, tick;
+ u_long adj, tick, tick_increment;
register_t s;
critical_enter();
adj = PCPU_GET(tickadj);
+ tick_increment = PCPU_GET(tickincrement);
s = intr_disable();
tick = rd(tick);
- wrtickcmpr(tick + tick_increment - adj, 0);
+ if (tick_increment != 0)
+ wrtickcmpr(tick + tick_increment - adj, 0);
+ else
+ wrtickcmpr(1L << 63, 0);
intr_restore(s);
tick_hardclock_common(tf, tick, adj);
critical_exit();
}
static void
-stick_hardclock(struct trapframe *tf)
+stick_intr(struct trapframe *tf)
{
- u_long adj, stick;
+ u_long adj, stick, tick_increment;
register_t s;
critical_enter();
adj = PCPU_GET(tickadj);
+ tick_increment = PCPU_GET(tickincrement);
s = intr_disable();
stick = rdstick();
- wrstickcmpr(stick + tick_increment - adj, 0);
+ if (tick_increment != 0)
+ wrstickcmpr(stick + tick_increment - adj, 0);
+ else
+ wrstickcmpr(1L << 63, 0);
intr_restore(s);
tick_hardclock_common(tf, stick, adj);
critical_exit();
@@ -234,10 +272,11 @@ stick_hardclock(struct trapframe *tf)
static inline void
tick_hardclock_common(struct trapframe *tf, u_long tick, u_long adj)
{
- u_long ref;
+ u_long ref, tick_increment;
long delta;
int count;
+ tick_increment = PCPU_GET(tickincrement);
ref = PCPU_GET(tickref);
delta = tick - ref;
count = 0;
@@ -248,6 +287,8 @@ tick_hardclock_common(struct trapframe *tf, u_long tick, u_long adj)
if (adj != 0)
adjust_ticks++;
count++;
+ if (tick_increment == 0)
+ break;
}
if (count > 0) {
adjust_missed += count - 1;
@@ -266,6 +307,13 @@ tick_hardclock_common(struct trapframe *tf, u_long tick, u_long adj)
}
static u_int
+stick_get_timecount(struct timecounter *tc)
+{
+
+ return ((u_int)rdstick());
+}
+
+static u_int
tick_get_timecount_up(struct timecounter *tc)
{
@@ -294,12 +342,28 @@ tick_get_timecount_mp(struct timecounter *tc)
}
#endif
-void
-tick_start(void)
+static int
+tick_et_start(struct eventtimer *et,
+ struct bintime *first, struct bintime *period)
{
+ u_long fdiv, div;
u_long base;
register_t s;
+ if (period != NULL) {
+ div = (tick_et.et_frequency * (period->frac >> 32)) >> 32;
+ if (period->sec != 0)
+ div += tick_et.et_frequency * period->sec;
+ } else
+ div = 0;
+ if (first != NULL) {
+ fdiv = (tick_et.et_frequency * (first->frac >> 32)) >> 32;
+ if (first->sec != 0)
+ fdiv += tick_et.et_frequency * first->sec;
+ } else
+ fdiv = div;
+ PCPU_SET(tickincrement, div);
+
/*
* Try to make the (S)TICK interrupts as synchronously as possible
* on all CPUs to avoid inaccuracies for migrating processes. Leave
@@ -312,14 +376,25 @@ tick_start(void)
base = rdstick();
else
base = rd(tick);
- base = roundup(base, tick_increment);
+ if (div != 0)
+ base = roundup(base, div);
PCPU_SET(tickref, base);
if (hardclock_use_stick != 0)
- wrstickcmpr(base + tick_increment, 0);
+ wrstickcmpr(base + fdiv, 0);
else
- wrtickcmpr(base + tick_increment, 0);
+ wrtickcmpr(base + fdiv, 0);
intr_restore(s);
critical_exit();
+ return (0);
+}
+
+static int
+tick_et_stop(struct eventtimer *et)
+{
+
+ PCPU_SET(tickincrement, 0);
+ tick_stop(PCPU_GET(impl));
+ return (0);
}
void
OpenPOWER on IntegriCloud