]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - 6/sys/sparc64/sparc64/tick.c
merge fix for boot-time hang on centos' xen
[FreeBSD/FreeBSD.git] / 6 / sys / sparc64 / sparc64 / tick.c
1 /*-
2  * Copyright (c) 2001 Jake Burkholder.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
33 #include <sys/bus.h>
34 #include <sys/interrupt.h>
35 #include <sys/pcpu.h>
36 #include <sys/sysctl.h>
37 #include <sys/timetc.h>
38
39 #include <machine/clock.h>
40 #include <machine/frame.h>
41 #include <machine/intr_machdep.h>
42 #include <machine/tick.h>
43 #include <machine/ver.h>
44
45 #define TICK_GRACE      10000
46
47 SYSCTL_NODE(_machdep, OID_AUTO, tick, CTLFLAG_RD, 0, "tick statistics");
48
49 static int adjust_edges = 0;
50 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_edges, CTLFLAG_RD, &adjust_edges,
51     0, "total number of times tick interrupts got more than 12.5% behind");
52
53 static int adjust_excess = 0;
54 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_excess, CTLFLAG_RD, &adjust_excess,
55     0, "total number of ignored tick interrupts");
56
57 static int adjust_missed = 0;
58 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_missed, CTLFLAG_RD, &adjust_missed,
59     0, "total number of missed tick interrupts");
60
61 static int adjust_ticks = 0;
62 SYSCTL_INT(_machdep_tick, OID_AUTO, adjust_ticks, CTLFLAG_RD, &adjust_ticks,
63     0, "total number of tick interrupts with adjustment");
64
65 static void tick_hardclock(struct clockframe *cf);
66
67 void
68 cpu_initclocks(void)
69 {
70
71         stathz = hz;
72         tick_start();
73 }
74
75 static inline void
76 tick_process(struct clockframe *cf)
77 {
78
79         if (curcpu == 0)
80                 hardclock(cf);
81         else
82                 hardclock_process(cf);
83         if (profprocs != 0)
84                 profclock(cf);
85         statclock(cf);
86 }
87
88 static void
89 tick_hardclock(struct clockframe *cf)
90 {
91         u_long adj, ref, tick;
92         long delta;
93         register_t s;
94         int count;
95
96         /*
97          * The sequence of reading the TICK register, calculating the value
98          * of the next tick and writing it to the TICK_CMPR register must not
99          * be interrupted, not even by an IPI, otherwise a value that is in
100          * the past could be written in the worst case, causing hardclock to
101          * stop.
102          */
103         adj = PCPU_GET(tickadj);
104         s = intr_disable();
105         tick = rd(tick);
106         wrtickcmpr(tick + tick_increment - adj, 0);
107         intr_restore(s);
108         ref = PCPU_GET(tickref);
109         delta = tick - ref;
110         count = 0;
111         while (delta >= tick_increment) {
112                 tick_process(cf);
113                 delta -= tick_increment;
114                 ref += tick_increment;
115                 if (adj != 0)
116                         adjust_ticks++;
117                 count++;
118         }
119         if (count > 0) {
120                 adjust_missed += count - 1;
121                 if (delta > (tick_increment >> 3)) {
122                         if (adj == 0)
123                                 adjust_edges++;
124                         adj = tick_increment >> 4;
125                 } else
126                         adj = 0;
127         } else {
128                 adj = 0;
129                 adjust_excess++;
130         }
131         PCPU_SET(tickref, ref);
132         PCPU_SET(tickadj, adj);
133 }
134
135 void
136 tick_init(u_long clock)
137 {
138
139         tick_freq = clock;
140         tick_MHz = clock / 1000000;
141         tick_increment = clock / hz;
142
143         /*
144          * UltraSparc II[e,i] based systems come up with the tick interrupt
145          * enabled and a handler that resets the tick counter, causing DELAY()
146          * to not work properly when used early in boot.
147          * UltraSPARC III based systems come up with the system tick interrupt
148          * enabled, causing an interrupt storm on startup since they are not
149          * handled.
150          */
151         tick_stop();
152 }
153
154 void
155 tick_start(void)
156 {
157         u_long base;
158         register_t s;
159
160         /*
161          * Avoid stopping of hardclock in terms of a lost tick interrupt
162          * by ensuring that the tick period is at least TICK_GRACE ticks.
163          * This check would be better placed in tick_init(), however we
164          * have to call tick_init() before cninit() in order to provide
165          * the low-level console drivers with a working DELAY() which in
166          * turn means we cannot use panic() in tick_init().
167          */
168         if (tick_increment < TICK_GRACE)
169                 panic("%s: HZ too high, decrease to at least %ld", __func__,
170                     tick_freq / TICK_GRACE);
171
172         if (curcpu == 0)
173                 intr_setup(PIL_TICK, (ih_func_t *)tick_hardclock, -1, NULL,
174                     NULL);
175
176         /*
177          * Try to make the tick interrupts as synchronously as possible on
178          * all CPUs to avoid inaccuracies for migrating processes. Leave out
179          * one tick to make sure that it is not missed.
180          */
181         PCPU_SET(tickadj, 0);
182         s = intr_disable();
183         base = rd(tick);
184         base = roundup(base, tick_increment);
185         PCPU_SET(tickref, base);
186         wrtickcmpr(base + tick_increment, 0);
187         intr_restore(s);
188 }
189
190 void
191 tick_stop(void)
192 {
193
194         if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
195                 wr(asr24, 1L << 63, 0);
196         wrtickcmpr(1L << 63, 0);
197 }