]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/sparc64/sparc64/tick.c
This commit was generated by cvs2svn to compensate for changes in r147824,
[FreeBSD/FreeBSD.git] / 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 *);
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 (PCPU_GET(cpuid) == 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, s, tick, ref;
92         long delta;
93         int count;
94
95         /*
96          * The sequence of reading the TICK register, calculating the value
97          * of the next tick and writing it to the TICK_CMPR register must not
98          * be interrupted, not even by an IPI, otherwise a value that is in
99          * the past could be written in the worst case, causing hardclock to
100          * stop.
101          */
102         adj = PCPU_GET(tickadj);
103         s = intr_disable();
104         tick = rd(tick);
105         wrtickcmpr(tick + tick_increment - adj, 0);
106         intr_restore(s);
107         ref = PCPU_GET(tickref);
108         delta = tick - ref;
109         count = 0;
110         while (delta >= tick_increment) {
111                 tick_process(cf);
112                 delta -= tick_increment;
113                 ref += tick_increment;
114                 if (adj != 0)
115                         adjust_ticks++;
116                 count++;
117         }
118         if (count > 0) {
119                 adjust_missed += count - 1;
120                 if (delta > (tick_increment >> 3)) {
121                         if (adj == 0)
122                                 adjust_edges++;
123                         adj = tick_increment >> 4;
124                 } else
125                         adj = 0;
126         } else {
127                 adj = 0;
128                 adjust_excess++;
129         }
130         PCPU_SET(tickref, ref);
131         PCPU_SET(tickadj, adj);
132 }
133
134 void
135 tick_init(u_long clock)
136 {
137
138         tick_freq = clock;
139         tick_MHz = clock / 1000000;
140         tick_increment = clock / hz;
141         /*
142          * Avoid stopping of hardclock in terms of a lost tick interrupt
143          * by ensuring that the tick period is at least TICK_GRACE ticks.
144          */
145         if (tick_increment < TICK_GRACE)
146                 panic("%s: HZ to high, decrease to at least %ld", __func__,
147                     clock / TICK_GRACE);
148
149         /*
150          * UltraSparc II[e,i] based systems come up with the tick interrupt
151          * enabled and a handler that resets the tick counter, causing DELAY()
152          * to not work properly when used early in boot.
153          * UltraSPARC III based systems come up with the system tick interrupt
154          * enabled, causing an interrupt storm on startup since they are not
155          * handled.
156          */
157         tick_stop();
158 }
159
160 void
161 tick_start(void)
162 {
163         u_long base, s;
164
165         if (PCPU_GET(cpuid) == 0)
166                 intr_setup(PIL_TICK, (ih_func_t *)tick_hardclock, -1, NULL,
167                     NULL);
168
169         /*
170          * Try to make the tick interrupts as synchronously as possible on
171          * all CPUs to avoid inaccuracies for migrating processes. Leave out
172          * one tick to make sure that it is not missed.
173          */
174         PCPU_SET(tickadj, 0);
175         s = intr_disable();
176         base = rd(tick);
177         base = roundup(base, tick_increment);
178         PCPU_SET(tickref, base);
179         wrtickcmpr(base + tick_increment, 0);
180         intr_restore(s);
181 }
182
183 void
184 tick_stop(void)
185 {
186
187         if (cpu_impl >= CPU_IMPL_ULTRASPARCIII)
188                 wr(asr24, 1L << 63, 0);
189         wrtickcmpr(1L << 63, 0);
190 }