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/timetc.h>
43 #include <dev/ofw/openfirm.h>
45 #include <machine/cpu.h>
46 #include <machine/frame.h>
47 #include <machine/intr_machdep.h>
48 #include <machine/tick.h>
49 #include <machine/ver.h>
51 /* 10000 ticks proved okay for 500MHz. */
52 #define TICK_GRACE(clock) ((clock) / 1000000 * 2 * 10)
54 #define TICK_QUALITY_MP 10
55 #define TICK_QUALITY_UP 1000
57 SYSCTL_NODE(_machdep, OID_AUTO, tick, CTLFLAG_RD, 0, "tick statistics");
59 static int adjust_edges = 0;
60 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_edges, CTLFLAG_RD, &adjust_edges,
61 0, "total number of times tick interrupts got more than 12.5% behind");
63 static int adjust_excess = 0;
64 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_excess, CTLFLAG_RD, &adjust_excess,
65 0, "total number of ignored tick interrupts");
67 static int adjust_missed = 0;
68 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_missed, CTLFLAG_RD, &adjust_missed,
69 0, "total number of missed tick interrupts");
71 static int adjust_ticks = 0;
72 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_ticks, CTLFLAG_RD, &adjust_ticks,
73 0, "total number of tick interrupts with adjustment");
75 u_int hardclock_use_stick = 0;
76 SYSCTL_INT(_machdep_tick, OID_AUTO, hardclock_use_stick, CTLFLAG_RD,
77 &hardclock_use_stick, 0, "hardclock uses STICK instead of TICK timer");
79 static struct timecounter tick_tc;
80 static u_long tick_increment;
82 static uint64_t tick_cputicks(void);
83 static timecounter_get_t tick_get_timecount_up;
85 static timecounter_get_t tick_get_timecount_mp;
87 static void tick_hardclock(struct trapframe *tf);
88 static void tick_hardclock_bbwar(struct trapframe *tf);
89 static inline void tick_hardclock_common(struct trapframe *tf, u_long tick,
91 static inline void tick_process(struct trapframe *tf);
92 static void stick_hardclock(struct trapframe *tf);
109 * Given that the STICK timers typically are driven at rather low
110 * frequencies they shouldn't be used except when really necessary.
112 if (hardclock_use_stick != 0) {
113 if (OF_getprop(OF_parent(PCPU_GET(node)), "stick-frequency",
114 &clock, sizeof(clock)) == -1)
115 panic("%s: could not determine STICK frequency", __func__);
116 intr_setup(PIL_TICK, stick_hardclock, -1, NULL, NULL);
118 * We don't provide a CPU ticker as long as the frequency
119 * supplied isn't actually used per-CPU.
122 clock = PCPU_GET(clock);
123 intr_setup(PIL_TICK, cpu_impl < CPU_IMPL_ULTRASPARCIII ?
124 tick_hardclock_bbwar : tick_hardclock, -1, NULL, NULL);
125 set_cputicker(tick_cputicks, clock, 0);
127 tick_increment = clock / hz;
129 * Avoid stopping of hardclock in terms of a lost (S)TICK interrupt
130 * by ensuring that the (S)TICK period is at least TICK_GRACE ticks.
132 if (tick_increment < TICK_GRACE(clock))
133 panic("%s: HZ too high, decrease to at least %d",
134 __func__, clock / TICK_GRACE(clock));
138 * Initialize the TICK-based timecounter. This must not happen
139 * before SI_SUB_INTRINSIC for tick_get_timecount_mp() to work.
141 tick_tc.tc_get_timecount = tick_get_timecount_up;
142 tick_tc.tc_poll_pps = NULL;
143 tick_tc.tc_counter_mask = ~0u;
144 tick_tc.tc_frequency = PCPU_GET(clock);
145 tick_tc.tc_name = "tick";
146 tick_tc.tc_quality = TICK_QUALITY_UP;
147 tick_tc.tc_priv = NULL;
150 * We (try to) sync the (S)TICK timers of APs with the BSP during
151 * their startup but not afterwards. The resulting drift can
152 * cause problems when the time is calculated based on (S)TICK
153 * values read on different CPUs. Thus we bind to the BSP for
154 * reading the register and use a low quality for the otherwise
155 * high quality (S)TICK timers in the MP case.
157 if (cpu_mp_probe()) {
158 tick_tc.tc_get_timecount = tick_get_timecount_mp;
159 tick_tc.tc_quality = TICK_QUALITY_MP;
166 tick_process(struct trapframe *tf)
170 hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
172 hardclock_cpu(TRAPF_USERMODE(tf));
174 profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
175 statclock(TRAPF_USERMODE(tf));
179 * NB: the sequence of reading the (S)TICK register, calculating the value
180 * of the next tick and writing it to the (S)TICK_COMPARE register must not
181 * be interrupted, not even by an IPI, otherwise a value that is in the past
182 * could be written in the worst case, causing hardclock to stop.
186 tick_hardclock(struct trapframe *tf)
192 adj = PCPU_GET(tickadj);
195 wr(tick_cmpr, tick + tick_increment - adj, 0);
197 tick_hardclock_common(tf, tick, adj);
202 tick_hardclock_bbwar(struct trapframe *tf)
208 adj = PCPU_GET(tickadj);
211 wrtickcmpr(tick + tick_increment - adj, 0);
213 tick_hardclock_common(tf, tick, adj);
218 stick_hardclock(struct trapframe *tf)
224 adj = PCPU_GET(tickadj);
227 wrstickcmpr(stick + tick_increment - adj, 0);
229 tick_hardclock_common(tf, stick, adj);
234 tick_hardclock_common(struct trapframe *tf, u_long tick, u_long adj)
240 ref = PCPU_GET(tickref);
243 while (delta >= tick_increment) {
245 delta -= tick_increment;
246 ref += tick_increment;
252 adjust_missed += count - 1;
253 if (delta > (tick_increment >> 3)) {
256 adj = tick_increment >> 4;
263 PCPU_SET(tickref, ref);
264 PCPU_SET(tickadj, adj);
268 tick_get_timecount_up(struct timecounter *tc)
271 return ((u_int)rd(tick));
276 tick_get_timecount_mp(struct timecounter *tc)
286 tick = tick_get_timecount_up(tc);
303 * Try to make the (S)TICK interrupts as synchronously as possible
304 * on all CPUs to avoid inaccuracies for migrating processes. Leave
305 * out one tick to make sure that it is not missed.
308 PCPU_SET(tickadj, 0);
310 if (hardclock_use_stick != 0)
314 base = roundup(base, tick_increment);
315 PCPU_SET(tickref, base);
316 if (hardclock_use_stick != 0)
317 wrstickcmpr(base + tick_increment, 0);
319 wrtickcmpr(base + tick_increment, 0);
328 if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
337 if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
338 wrstickcmpr(1L << 63, 0);
339 wrtickcmpr(1L << 63, 0);