2 * Copyright (c) 2001 Jake Burkholder.
3 * Copyright (c) 2005, 2008 Marius Strobl <marius@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/kernel.h>
35 #include <sys/mutex.h>
38 #include <sys/sched.h>
40 #include <sys/sysctl.h>
41 #include <sys/timeet.h>
42 #include <sys/timetc.h>
44 #include <dev/ofw/openfirm.h>
49 #include <machine/cpu.h>
50 #include <machine/frame.h>
51 #include <machine/intr_machdep.h>
52 #include <machine/smp.h>
53 #include <machine/tick.h>
54 #include <machine/ver.h>
56 #define TICK_QUALITY_MP 10
57 #define TICK_QUALITY_UP 1000
59 static SYSCTL_NODE(_machdep, OID_AUTO, tick, CTLFLAG_RD, 0, "tick statistics");
61 static int adjust_edges = 0;
62 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_edges, CTLFLAG_RD, &adjust_edges,
63 0, "total number of times tick interrupts got more than 12.5% behind");
65 static int adjust_excess = 0;
66 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_excess, CTLFLAG_RD, &adjust_excess,
67 0, "total number of ignored tick interrupts");
69 static int adjust_missed = 0;
70 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_missed, CTLFLAG_RD, &adjust_missed,
71 0, "total number of missed tick interrupts");
73 static int adjust_ticks = 0;
74 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_ticks, CTLFLAG_RD, &adjust_ticks,
75 0, "total number of tick interrupts with adjustment");
77 u_int tick_et_use_stick = 0;
78 SYSCTL_INT(_machdep_tick, OID_AUTO, tick_et_use_stick, CTLFLAG_RD,
79 &tick_et_use_stick, 0, "tick event timer uses STICK instead of TICK");
81 typedef uint64_t rd_tick_t(void);
82 static rd_tick_t *rd_tick;
83 typedef void wr_tick_cmpr_t(uint64_t);
84 static wr_tick_cmpr_t *wr_tick_cmpr;
86 static struct timecounter stick_tc;
87 static struct eventtimer tick_et;
88 static struct timecounter tick_tc;
91 static timecounter_get_t stick_get_timecount_mp;
93 static timecounter_get_t stick_get_timecount_up;
94 static rd_tick_t stick_rd;
95 static wr_tick_cmpr_t stick_wr_cmpr;
96 static int tick_et_start(struct eventtimer *et, struct bintime *first,
97 struct bintime *period);
98 static int tick_et_stop(struct eventtimer *et);
100 static timecounter_get_t tick_get_timecount_mp;
102 static timecounter_get_t tick_get_timecount_up;
103 static void tick_intr(struct trapframe *tf);
104 static inline void tick_process(struct trapframe *tf);
105 static rd_tick_t tick_rd;
106 static wr_tick_cmpr_t tick_wr_cmpr;
107 static wr_tick_cmpr_t tick_wr_cmpr_bbwar;
108 static uint64_t tick_cputicks(void);
118 stick_wr_cmpr(uint64_t tick)
121 wrstickcmpr(tick, 0);
132 tick_wr_cmpr(uint64_t tick_cmpr)
135 wrtickcmpr(tick_cmpr, 0);
139 tick_wr_cmpr_bbwar(uint64_t tick_cmpr)
142 wrtickcmpr_bbwar(tick_cmpr, 0);
155 uint32_t clock, sclock;
157 clock = PCPU_GET(clock);
159 if (PCPU_GET(impl) == CPU_IMPL_SPARC64V ||
160 PCPU_GET(impl) >= CPU_IMPL_ULTRASPARCIII) {
161 if (OF_getprop(OF_peer(0), "stick-frequency", &sclock,
162 sizeof(sclock)) == -1) {
163 panic("%s: could not determine STICK frequency",
168 * Given that the STICK timers typically are driven at rather low
169 * frequencies they shouldn't be used except when really necessary.
171 if (tick_et_use_stick != 0) {
173 wr_tick_cmpr = stick_wr_cmpr;
175 * We don't provide a CPU ticker as long as the frequency
176 * supplied isn't actually used per-CPU.
180 if (PCPU_GET(impl) >= CPU_IMPL_ULTRASPARCI &&
181 PCPU_GET(impl) < CPU_IMPL_ULTRASPARCIII)
182 wr_tick_cmpr = tick_wr_cmpr_bbwar;
184 wr_tick_cmpr = tick_wr_cmpr;
185 set_cputicker(tick_cputicks, clock, 0);
187 intr_setup(PIL_TICK, tick_intr, -1, NULL, NULL);
190 * Initialize the (S)TICK-based timecounter(s).
191 * Note that we (try to) sync the (S)TICK timers of APs with the BSP
192 * during their startup but not afterwards. The resulting drift can
193 * cause problems when the time is calculated based on (S)TICK values
194 * read on different CPUs. Thus we always read the register on the
195 * BSP (if necessary via an IPI as sched_bind(9) isn't available in
196 * all circumstances) and use a low quality for the otherwise high
197 * quality (S)TICK timers in the MP case.
199 tick_tc.tc_get_timecount = tick_get_timecount_up;
200 tick_tc.tc_counter_mask = ~0u;
201 tick_tc.tc_frequency = clock;
202 tick_tc.tc_name = "tick";
203 tick_tc.tc_quality = TICK_QUALITY_UP;
205 if (cpu_mp_probe()) {
206 tick_tc.tc_get_timecount = tick_get_timecount_mp;
207 tick_tc.tc_quality = TICK_QUALITY_MP;
212 stick_tc.tc_get_timecount = stick_get_timecount_up;
213 stick_tc.tc_counter_mask = ~0u;
214 stick_tc.tc_frequency = sclock;
215 stick_tc.tc_name = "stick";
216 stick_tc.tc_quality = TICK_QUALITY_UP;
218 if (cpu_mp_probe()) {
219 stick_tc.tc_get_timecount = stick_get_timecount_mp;
220 stick_tc.tc_quality = TICK_QUALITY_MP;
225 tick_et.et_name = tick_et_use_stick ? "stick" : "tick";
226 tick_et.et_flags = ET_FLAGS_PERIODIC | ET_FLAGS_ONESHOT |
228 tick_et.et_quality = 1000;
229 tick_et.et_frequency = tick_et_use_stick ? sclock : clock;
230 tick_et.et_min_period.sec = 0;
231 tick_et.et_min_period.frac = 0x00010000LLU << 32; /* To be safe. */
232 tick_et.et_max_period.sec = 3600 * 24; /* No practical limit. */
233 tick_et.et_max_period.frac = 0;
234 tick_et.et_start = tick_et_start;
235 tick_et.et_stop = tick_et_stop;
236 tick_et.et_priv = NULL;
237 et_register(&tick_et);
239 cpu_initclocks_bsp();
243 tick_process(struct trapframe *tf)
245 struct trapframe *oldframe;
249 if (tick_et.et_active) {
251 oldframe = td->td_intr_frame;
252 td->td_intr_frame = tf;
253 tick_et.et_event_cb(&tick_et, tick_et.et_arg);
254 td->td_intr_frame = oldframe;
260 tick_intr(struct trapframe *tf)
262 u_long adj, ref, tick, tick_increment;
267 tick_increment = PCPU_GET(tickincrement);
268 if (tick_increment != 0) {
270 * NB: the sequence of reading the (S)TICK register,
271 * calculating the value of the next tick and writing it to
272 * the (S)TICK_COMPARE register must not be interrupted, not
273 * even by an IPI, otherwise a value that is in the past could
274 * be written in the worst case and thus causing the periodic
278 adj = PCPU_GET(tickadj);
280 wr_tick_cmpr(tick + tick_increment - adj);
282 ref = PCPU_GET(tickref);
285 while (delta >= tick_increment) {
287 delta -= tick_increment;
288 ref += tick_increment;
294 adjust_missed += count - 1;
295 if (delta > (tick_increment >> 3)) {
298 adj = tick_increment >> 4;
305 PCPU_SET(tickref, ref);
306 PCPU_SET(tickadj, adj);
312 stick_get_timecount_up(struct timecounter *tc)
315 return ((u_int)rdstick());
319 tick_get_timecount_up(struct timecounter *tc)
322 return ((u_int)rd(tick));
327 stick_get_timecount_mp(struct timecounter *tc)
335 ipi_wait(ipi_rd(0, tl_ipi_stick_rd, &stick));
341 tick_get_timecount_mp(struct timecounter *tc)
349 ipi_wait(ipi_rd(0, tl_ipi_tick_rd, &tick));
356 tick_et_start(struct eventtimer *et, struct bintime *first,
357 struct bintime *period)
359 u_long base, div, fdiv;
362 if (period != NULL) {
363 div = (tick_et.et_frequency * (period->frac >> 32)) >> 32;
364 if (period->sec != 0)
365 div += tick_et.et_frequency * period->sec;
369 fdiv = (tick_et.et_frequency * (first->frac >> 32)) >> 32;
371 fdiv += tick_et.et_frequency * first->sec;
374 PCPU_SET(tickincrement, div);
377 * Try to make the (S)TICK interrupts as synchronously as possible
378 * on all CPUs to avoid inaccuracies for migrating processes. Leave
379 * out one tick to make sure that it is not missed.
384 PCPU_SET(tickadj, 0);
385 base = roundup(base, div);
387 PCPU_SET(tickref, base);
388 wr_tick_cmpr(base + fdiv);
394 tick_et_stop(struct eventtimer *et)
397 PCPU_SET(tickincrement, 0);
398 tick_stop(PCPU_GET(impl));
403 tick_clear(u_int cpu_impl)
406 if (cpu_impl == CPU_IMPL_SPARC64V ||
407 cpu_impl >= CPU_IMPL_ULTRASPARCIII)
413 tick_stop(u_int cpu_impl)
416 if (cpu_impl == CPU_IMPL_SPARC64V ||
417 cpu_impl >= CPU_IMPL_ULTRASPARCIII)
418 wrstickcmpr(1L << 63, 0);
419 wrtickcmpr(1L << 63, 0);