remove schedintr_4m(), and go back to only having the level 14 timer call statclock/schedclock. the randomness for this clock makes the hardclock() call very jittery. instead of this, trigger a softintr IPI at level 10 on non-primary CPUs from the primary CPU's clock interrupt (at level 10.) this cleans up the generic sparc timer code a little as well. this makes the time goes backwards problem *much* less frequent, but i still see it sometimes.diff -r1.31 -r1.32 src/sys/arch/sparc/sparc/timer.c
(mrg)
--- src/sys/arch/sparc/sparc/timer.c 2013/10/19 19:40:23 1.31
+++ src/sys/arch/sparc/sparc/timer.c 2014/01/19 00:22:33 1.32
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: timer.c,v 1.31 2013/10/19 19:40:23 mrg Exp $ */ | 1 | /* $NetBSD: timer.c,v 1.32 2014/01/19 00:22:33 mrg Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1992, 1993 | 4 | * Copyright (c) 1992, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * Copyright (c) 1994 Gordon W. Ross | 6 | * Copyright (c) 1994 Gordon W. Ross | |
7 | * Copyright (c) 1993 Adam Glass | 7 | * Copyright (c) 1993 Adam Glass | |
8 | * Copyright (c) 1996 Paul Kranenburg | 8 | * Copyright (c) 1996 Paul Kranenburg | |
9 | * Copyright (c) 1996 | 9 | * Copyright (c) 1996 | |
10 | * The President and Fellows of Harvard College. All rights reserved. | 10 | * The President and Fellows of Harvard College. All rights reserved. | |
11 | * | 11 | * | |
12 | * This software was developed by the Computer Systems Engineering group | 12 | * This software was developed by the Computer Systems Engineering group | |
13 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | 13 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | |
14 | * contributed to Berkeley. | 14 | * contributed to Berkeley. | |
@@ -50,54 +50,54 @@ | @@ -50,54 +50,54 @@ | |||
50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
51 | * SUCH DAMAGE. | 51 | * SUCH DAMAGE. | |
52 | * | 52 | * | |
53 | * @(#)clock.c 8.1 (Berkeley) 6/11/93 | 53 | * @(#)clock.c 8.1 (Berkeley) 6/11/93 | |
54 | */ | 54 | */ | |
55 | 55 | |||
56 | /* | 56 | /* | |
57 | * Kernel clocks provided by "timer" device. The hardclock is provided by | 57 | * Kernel clocks provided by "timer" device. The hardclock is provided by | |
58 | * the timer register (aka system counter). The statclock is provided by | 58 | * the timer register (aka system counter). The statclock is provided by | |
59 | * per CPU counter register(s) (aka processor counter(s)). | 59 | * per CPU counter register(s) (aka processor counter(s)). | |
60 | */ | 60 | */ | |
61 | 61 | |||
62 | #include <sys/cdefs.h> | 62 | #include <sys/cdefs.h> | |
63 | __KERNEL_RCSID(0, "$NetBSD: timer.c,v 1.31 2013/10/19 19:40:23 mrg Exp $"); | 63 | __KERNEL_RCSID(0, "$NetBSD: timer.c,v 1.32 2014/01/19 00:22:33 mrg Exp $"); | |
64 | 64 | |||
65 | #include <sys/param.h> | 65 | #include <sys/param.h> | |
66 | #include <sys/kernel.h> | 66 | #include <sys/kernel.h> | |
67 | #include <sys/device.h> | 67 | #include <sys/device.h> | |
68 | #include <sys/systm.h> | 68 | #include <sys/systm.h> | |
69 | #include <sys/timetc.h> | 69 | #include <sys/timetc.h> | |
70 | 70 | |||
71 | #include <machine/autoconf.h> | 71 | #include <machine/autoconf.h> | |
72 | #include <sys/bus.h> | 72 | #include <sys/bus.h> | |
73 | 73 | |||
74 | #include <sparc/sparc/timerreg.h> | 74 | #include <sparc/sparc/timerreg.h> | |
75 | #include <sparc/sparc/timervar.h> | 75 | #include <sparc/sparc/timervar.h> | |
76 | 76 | |||
77 | static struct intrhand level10; | 77 | static struct intrhand level10; | |
78 | static struct intrhand level14; | 78 | static struct intrhand level14; | |
79 | 79 | |||
80 | static u_int timer_get_timecount(struct timecounter *); | 80 | static u_int timer_get_timecount(struct timecounter *); | |
81 | 81 | |||
82 | void *sched_cookie; | 82 | void *sched_cookie; | |
83 | 83 | |||
84 | /* | 84 | /* | |
85 | * timecounter local state | 85 | * timecounter local state | |
86 | */ | 86 | */ | |
87 | static struct counter { | 87 | static struct counter { | |
88 | volatile u_int *cntreg; /* counter register */ | 88 | volatile u_int *cntreg; /* counter register */ | |
89 | u_int limit; /* limit we count up to */ | 89 | u_int limit; /* limit we count up to */ | |
90 | u_int offset; /* accumulated offet due to wraps */ | 90 | u_int offset; /* accumulated offset due to wraps */ | |
91 | u_int shift; /* scaling for valid bits */ | 91 | u_int shift; /* scaling for valid bits */ | |
92 | u_int mask; /* valid bit mask */ | 92 | u_int mask; /* valid bit mask */ | |
93 | } cntr; | 93 | } cntr; | |
94 | 94 | |||
95 | /* | 95 | /* | |
96 | * define timecounter | 96 | * define timecounter | |
97 | */ | 97 | */ | |
98 | 98 | |||
99 | static struct timecounter counter_timecounter = { | 99 | static struct timecounter counter_timecounter = { | |
100 | timer_get_timecount, /* get_timecount */ | 100 | timer_get_timecount, /* get_timecount */ | |
101 | 0, /* no poll_pps */ | 101 | 0, /* no poll_pps */ | |
102 | ~0u, /* counter_mask */ | 102 | ~0u, /* counter_mask */ | |
103 | 0, /* frequency - set at initialisation */ | 103 | 0, /* frequency - set at initialisation */ | |
@@ -107,32 +107,31 @@ static struct timecounter counter_timeco | @@ -107,32 +107,31 @@ static struct timecounter counter_timeco | |||
107 | }; | 107 | }; | |
108 | 108 | |||
109 | /* | 109 | /* | |
110 | * timer_get_timecount provide current counter value | 110 | * timer_get_timecount provide current counter value | |
111 | */ | 111 | */ | |
112 | static u_int | 112 | static u_int | |
113 | timer_get_timecount(struct timecounter *tc) | 113 | timer_get_timecount(struct timecounter *tc) | |
114 | { | 114 | { | |
115 | struct counter *ctr = (struct counter *)tc->tc_priv; | 115 | struct counter *ctr = (struct counter *)tc->tc_priv; | |
116 | 116 | |||
117 | u_int c, res, r; | 117 | u_int c, res, r; | |
118 | int s; | 118 | int s; | |
119 | 119 | |||
120 | ||||
121 | s = splhigh(); | 120 | s = splhigh(); | |
122 | 121 | |||
123 | res = c = *ctr->cntreg; | 122 | res = c = *ctr->cntreg; | |
124 | 123 | |||
125 | res &= ~TMR_LIMIT; | 124 | res &= ~TMR_LIMIT; | |
126 | 125 | |||
127 | if (c != res) { | 126 | if (c != res) { | |
128 | r = ctr->limit; | 127 | r = ctr->limit; | |
129 | } else { | 128 | } else { | |
130 | r = 0; | 129 | r = 0; | |
131 | } | 130 | } | |
132 | 131 | |||
133 | res >>= ctr->shift; | 132 | res >>= ctr->shift; | |
134 | res &= ctr->mask; | 133 | res &= ctr->mask; | |
135 | 134 | |||
136 | res += r + ctr->offset; | 135 | res += r + ctr->offset; | |
137 | 136 | |||
138 | splx(s); | 137 | splx(s); | |
@@ -145,27 +144,26 @@ tickle_tc(void) | @@ -145,27 +144,26 @@ tickle_tc(void) | |||
145 | { | 144 | { | |
146 | if (timecounter->tc_get_timecount == timer_get_timecount) { | 145 | if (timecounter->tc_get_timecount == timer_get_timecount) { | |
147 | cntr.offset += cntr.limit; | 146 | cntr.offset += cntr.limit; | |
148 | } | 147 | } | |
149 | } | 148 | } | |
150 | 149 | |||
151 | /* | 150 | /* | |
152 | * sun4/sun4c/sun4m common timer attach code | 151 | * sun4/sun4c/sun4m common timer attach code | |
153 | */ | 152 | */ | |
154 | void | 153 | void | |
155 | timerattach(volatile int *cntreg, volatile int *limreg) | 154 | timerattach(volatile int *cntreg, volatile int *limreg) | |
156 | { | 155 | { | |
157 | u_int prec = 0, t0; | 156 | u_int prec = 0, t0; | |
158 | void (*sched_intr_fn)(void *); | |||
159 | 157 | |||
160 | /* | 158 | /* | |
161 | * Calibrate delay() by tweaking the magic constant | 159 | * Calibrate delay() by tweaking the magic constant | |
162 | * until a delay(100) actually reads (at least) 100 us on the clock. | 160 | * until a delay(100) actually reads (at least) 100 us on the clock. | |
163 | * Note: sun4m clocks tick with 500ns periods. | 161 | * Note: sun4m clocks tick with 500ns periods. | |
164 | */ | 162 | */ | |
165 | for (timerblurb = 1; ; timerblurb++) { | 163 | for (timerblurb = 1; ; timerblurb++) { | |
166 | int discard; | 164 | int discard; | |
167 | u_int t1; | 165 | u_int t1; | |
168 | 166 | |||
169 | /* Reset counter register by writing some large limit value */ | 167 | /* Reset counter register by writing some large limit value */ | |
170 | discard = *limreg; | 168 | discard = *limreg; | |
171 | __USE(discard); | 169 | __USE(discard); | |
@@ -188,56 +186,50 @@ timerattach(volatile int *cntreg, volati | @@ -188,56 +186,50 @@ timerattach(volatile int *cntreg, volati | |||
188 | } | 186 | } | |
189 | 187 | |||
190 | /* find lowest active bit */ | 188 | /* find lowest active bit */ | |
191 | for (t0 = 0; t0 < TMR_SHIFT; t0++) | 189 | for (t0 = 0; t0 < TMR_SHIFT; t0++) | |
192 | if ((1 << t0) & prec) | 190 | if ((1 << t0) & prec) | |
193 | break; | 191 | break; | |
194 | 192 | |||
195 | cntr.shift = t0; | 193 | cntr.shift = t0; | |
196 | cntr.mask = (1 << (31-t0))-1; | 194 | cntr.mask = (1 << (31-t0))-1; | |
197 | counter_timecounter.tc_frequency = 1000000 * (TMR_SHIFT - t0 + 1); | 195 | counter_timecounter.tc_frequency = 1000000 * (TMR_SHIFT - t0 + 1); | |
198 | 196 | |||
199 | printf(": delay constant %d, frequency = %" PRIu64 " Hz\n", | 197 | printf(": delay constant %d, frequency = %" PRIu64 " Hz\n", | |
200 | timerblurb, counter_timecounter.tc_frequency); | 198 | timerblurb, counter_timecounter.tc_frequency); | |
199 | printf("timer: limit %u shift %u mask %x\n", cntr.limit, cntr.shift, cntr.mask); | |||
201 | 200 | |||
202 | #if defined(SUN4) || defined(SUN4C) | 201 | #if defined(SUN4) || defined(SUN4C) | |
203 | if (CPU_ISSUN4 || CPU_ISSUN4C) { | 202 | if (CPU_ISSUN4 || CPU_ISSUN4C) { | |
204 | timer_init = timer_init_4; | 203 | timer_init = timer_init_4; | |
205 | sched_intr_fn = schedintr; | |||
206 | level10.ih_fun = clockintr_4; | 204 | level10.ih_fun = clockintr_4; | |
207 | level14.ih_fun = statintr_4; | 205 | level14.ih_fun = statintr_4; | |
208 | cntr.limit = tmr_ustolim(tick); | 206 | cntr.limit = tmr_ustolim(tick); | |
209 | } | 207 | } | |
210 | #endif | 208 | #endif | |
211 | #if defined(SUN4M) | 209 | #if defined(SUN4M) | |
212 | if (CPU_ISSUN4M) { | 210 | if (CPU_ISSUN4M) { | |
213 | timer_init = timer_init_4m; | 211 | timer_init = timer_init_4m; | |
214 | #if defined(MULTIPROCESSOR) | |||
215 | if (sparc_ncpus > 1) | |||
216 | sched_intr_fn = schedintr_4m; | |||
217 | else | |||
218 | #endif | |||
219 | sched_intr_fn = schedintr; | |||
220 | level10.ih_fun = clockintr_4m; | 212 | level10.ih_fun = clockintr_4m; | |
221 | level14.ih_fun = statintr_4m; | 213 | level14.ih_fun = statintr_4m; | |
222 | cntr.limit = tmr_ustolim4m(tick); | 214 | cntr.limit = tmr_ustolim4m(tick); | |
223 | } | 215 | } | |
224 | #endif | 216 | #endif | |
225 | /* link interrupt handlers */ | 217 | /* link interrupt handlers */ | |
226 | intr_establish(10, 0, &level10, NULL, true); | 218 | intr_establish(10, 0, &level10, NULL, true); | |
227 | intr_establish(14, 0, &level14, NULL, true); | 219 | intr_establish(14, 0, &level14, NULL, true); | |
228 | 220 | |||
229 | /* Establish a soft interrupt at a lower level for schedclock */ | 221 | /* Establish a soft interrupt at a lower level for schedclock */ | |
230 | sched_cookie = sparc_softintr_establish(IPL_SCHED, sched_intr_fn, NULL); | 222 | sched_cookie = sparc_softintr_establish(IPL_SCHED, schedintr, NULL); | |
231 | if (sched_cookie == NULL) | 223 | if (sched_cookie == NULL) | |
232 | panic("timerattach: cannot establish schedintr"); | 224 | panic("timerattach: cannot establish schedintr"); | |
233 | 225 | |||
234 | cntr.cntreg = cntreg; | 226 | cntr.cntreg = cntreg; | |
235 | cntr.limit >>= cntr.shift; | 227 | cntr.limit >>= cntr.shift; | |
236 | 228 | |||
237 | tc_init(&counter_timecounter); | 229 | tc_init(&counter_timecounter); | |
238 | } | 230 | } | |
239 | 231 | |||
240 | /* | 232 | /* | |
241 | * Both sun4 and sun4m can attach a timer on obio. | 233 | * Both sun4 and sun4m can attach a timer on obio. | |
242 | * The sun4m OPENPROM calls the timer the "counter". | 234 | * The sun4m OPENPROM calls the timer the "counter". | |
243 | * The sun4 timer must be probed. | 235 | * The sun4 timer must be probed. |
--- src/sys/arch/sparc/sparc/timer_sun4m.c 2013/11/16 23:54:01 1.29
+++ src/sys/arch/sparc/sparc/timer_sun4m.c 2014/01/19 00:22:33 1.30
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: timer_sun4m.c,v 1.29 2013/11/16 23:54:01 mrg Exp $ */ | 1 | /* $NetBSD: timer_sun4m.c,v 1.30 2014/01/19 00:22:33 mrg Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1992, 1993 | 4 | * Copyright (c) 1992, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * Copyright (c) 1994 Gordon W. Ross | 6 | * Copyright (c) 1994 Gordon W. Ross | |
7 | * Copyright (c) 1993 Adam Glass | 7 | * Copyright (c) 1993 Adam Glass | |
8 | * Copyright (c) 1996 Paul Kranenburg | 8 | * Copyright (c) 1996 Paul Kranenburg | |
9 | * Copyright (c) 1996 | 9 | * Copyright (c) 1996 | |
10 | * The President and Fellows of Harvard College. All rights reserved. | 10 | * The President and Fellows of Harvard College. All rights reserved. | |
11 | * | 11 | * | |
12 | * This software was developed by the Computer Systems Engineering group | 12 | * This software was developed by the Computer Systems Engineering group | |
13 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | 13 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | |
14 | * contributed to Berkeley. | 14 | * contributed to Berkeley. | |
@@ -48,115 +48,140 @@ | @@ -48,115 +48,140 @@ | |||
48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | 48 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | 49 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 50 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
51 | * SUCH DAMAGE. | 51 | * SUCH DAMAGE. | |
52 | * | 52 | * | |
53 | * @(#)clock.c 8.1 (Berkeley) 6/11/93 | 53 | * @(#)clock.c 8.1 (Berkeley) 6/11/93 | |
54 | */ | 54 | */ | |
55 | 55 | |||
56 | /* | 56 | /* | |
57 | * Sun4m timer support. | 57 | * Sun4m timer support. | |
58 | */ | 58 | */ | |
59 | 59 | |||
60 | #include <sys/cdefs.h> | 60 | #include <sys/cdefs.h> | |
61 | __KERNEL_RCSID(0, "$NetBSD: timer_sun4m.c,v 1.29 2013/11/16 23:54:01 mrg Exp $"); | 61 | __KERNEL_RCSID(0, "$NetBSD: timer_sun4m.c,v 1.30 2014/01/19 00:22:33 mrg Exp $"); | |
62 | 62 | |||
63 | #include <sys/param.h> | 63 | #include <sys/param.h> | |
64 | #include <sys/kernel.h> | 64 | #include <sys/kernel.h> | |
65 | #include <sys/device.h> | 65 | #include <sys/device.h> | |
66 | #include <sys/systm.h> | 66 | #include <sys/systm.h> | |
67 | #include <sys/cpu.h> | 67 | #include <sys/cpu.h> | |
68 | 68 | |||
69 | #include <machine/autoconf.h> | 69 | #include <machine/autoconf.h> | |
70 | #include <sys/bus.h> | 70 | #include <sys/bus.h> | |
71 | 71 | |||
72 | #include <sparc/sparc/vaddrs.h> | 72 | #include <sparc/sparc/vaddrs.h> | |
73 | #include <sparc/sparc/cpuvar.h> | 73 | #include <sparc/sparc/cpuvar.h> | |
74 | #include <sparc/sparc/timerreg.h> | 74 | #include <sparc/sparc/timerreg.h> | |
75 | #include <sparc/sparc/timervar.h> | 75 | #include <sparc/sparc/timervar.h> | |
76 | 76 | |||
77 | struct timer_4m *timerreg4m; | 77 | struct timer_4m *timerreg4m; | |
78 | #define counterreg4m cpuinfo.counterreg_4m | 78 | #define counterreg4m cpuinfo.counterreg_4m | |
79 | 79 | |||
80 | /* | 80 | /* | |
81 | * SMP hardclock handler. | |||
82 | */ | |||
83 | #define IPL_HARDCLOCK 10 | |||
84 | ||||
85 | /* | |||
81 | * Set up the real-time and statistics clocks. | 86 | * Set up the real-time and statistics clocks. | |
82 | * Leave stathz 0 only if no alternative timer is available. | 87 | * Leave stathz 0 only if no alternative timer is available. | |
83 | * | 88 | * | |
84 | * The frequencies of these clocks must be an even number of microseconds. | 89 | * The frequencies of these clocks must be an even number of microseconds. | |
85 | */ | 90 | */ | |
86 | void | 91 | void | |
87 | timer_init_4m(void) | 92 | timer_init_4m(void) | |
88 | { | 93 | { | |
89 | struct cpu_info *cpi; | 94 | struct cpu_info *cpi; | |
90 | CPU_INFO_ITERATOR n; | 95 | CPU_INFO_ITERATOR n; | |
91 | 96 | |||
92 | timerreg4m->t_limit = tmr_ustolim4m(tick); | 97 | timerreg4m->t_limit = tmr_ustolim4m(tick); | |
93 | for (CPU_INFO_FOREACH(n, cpi)) { | 98 | for (CPU_INFO_FOREACH(n, cpi)) { | |
94 | cpi->counterreg_4m->t_limit = tmr_ustolim4m(statint); | 99 | cpi->counterreg_4m->t_limit = tmr_ustolim4m(statint); | |
95 | } | 100 | } | |
96 | icr_si_bic(SINTR_T); | 101 | icr_si_bic(SINTR_T); | |
97 | } | 102 | } | |
98 | 103 | |||
99 | void | 104 | #ifdef MULTIPROCESSOR | |
100 | schedintr_4m(void *v) | 105 | /* | |
106 | * Handle SMP hardclock() calling for this CPU. | |||
107 | */ | |||
108 | static void | |||
109 | hardclock_ipi(void *cap) | |||
101 | { | 110 | { | |
111 | int s = splsched(); | |||
102 | 112 | |||
103 | kpreempt_disable(); | 113 | hardclock((struct clockframe *)cap); | |
114 | splx(s); | |||
115 | } | |||
116 | #endif | |||
117 | ||||
118 | /* | |||
119 | * Call hardclock on all CPUs. | |||
120 | */ | |||
121 | static void | |||
122 | handle_hardclock(struct clockframe *cap) | |||
123 | { | |||
124 | int s; | |||
104 | #ifdef MULTIPROCESSOR | 125 | #ifdef MULTIPROCESSOR | |
105 | /* | 126 | struct cpu_info *cpi; | |
106 | * We call hardclock() here so that we make sure it is called on | 127 | CPU_INFO_ITERATOR n; | |
107 | * all CPUs. This function ends up being called on sun4m systems | |||
108 | * every tick. | |||
109 | */ | |||
110 | if (!CPU_IS_PRIMARY(curcpu())) | |||
111 | hardclock(v); | |||
112 | 128 | |||
113 | /* | 129 | for (CPU_INFO_FOREACH(n, cpi)) { | |
114 | * The factor 8 is only valid for stathz==100. | 130 | if (cpi == cpuinfo.ci_self) { | |
115 | * See also clock.c | 131 | KASSERT(CPU_IS_PRIMARY(cpi)); | |
116 | */ | 132 | continue; | |
117 | if ((++cpuinfo.ci_schedstate.spc_schedticks & 7) == 0 && schedhz != 0) | 133 | } | |
134 | ||||
135 | raise_ipi(cpi, IPL_HARDCLOCK); | |||
136 | } | |||
118 | #endif | 137 | #endif | |
119 | schedclock(curlwp); | 138 | s = splsched(); | |
120 | kpreempt_enable(); | 139 | hardclock(cap); | |
140 | splx(s); | |||
121 | } | 141 | } | |
122 | 142 | |||
123 | ||||
124 | /* | 143 | /* | |
125 | * Level 10 (clock) interrupts from system counter. | 144 | * Level 10 (clock) interrupts from system counter. | |
126 | */ | 145 | */ | |
127 | int | 146 | int | |
128 | clockintr_4m(void *cap) | 147 | clockintr_4m(void *cap) | |
129 | { | 148 | { | |
130 | 149 | |||
131 | KASSERT(CPU_IS_PRIMARY(curcpu())); | |||
132 | /* | 150 | /* | |
133 | * XXX this needs to be fixed in a more general way | 151 | * XXX this needs to be fixed in a more general way | |
134 | * problem is that the kernel enables interrupts and THEN | 152 | * problem is that the kernel enables interrupts and THEN | |
135 | * sets up clocks. In between there's an opportunity to catch | 153 | * sets up clocks. In between there's an opportunity to catch | |
136 | * a timer interrupt - if we call hardclock() at that point we'll | 154 | * a timer interrupt - if we call hardclock() at that point we'll | |
137 | * panic | 155 | * panic | |
138 | * so for now just bail when cold | 156 | * so for now just bail when cold | |
139 | * | 157 | * | |
140 | * For MP, we defer calling hardclock() to the schedintr so | 158 | * For MP, we defer calling hardclock() to the schedintr so | |
141 | * that we call it on all cpus. | 159 | * that we call it on all cpus. | |
142 | */ | 160 | */ | |
143 | if (cold) | 161 | if (cold) | |
144 | return 0; | 162 | return 0; | |
145 | kpreempt_disable(); | 163 | kpreempt_disable(); | |
146 | /* read the limit register to clear the interrupt */ | 164 | /* read the limit register to clear the interrupt */ | |
147 | *((volatile int *)&timerreg4m->t_limit); | 165 | *((volatile int *)&timerreg4m->t_limit); | |
148 | tickle_tc(); | 166 | tickle_tc(); | |
149 | hardclock((struct clockframe *)cap); | 167 | ||
168 | /* | |||
169 | * We don't have a system-clock per-cpu, and we'd like to keep | |||
170 | * the per-cpu timer for the statclock, so, send an IPI to | |||
171 | * everyone to call hardclock. | |||
172 | */ | |||
173 | handle_hardclock(cap); | |||
174 | ||||
150 | kpreempt_enable(); | 175 | kpreempt_enable(); | |
151 | return (1); | 176 | return (1); | |
152 | } | 177 | } | |
153 | 178 | |||
154 | /* | 179 | /* | |
155 | * Level 14 (stat clock) interrupts from processor counter. | 180 | * Level 14 (stat clock) interrupts from processor counter. | |
156 | */ | 181 | */ | |
157 | int | 182 | int | |
158 | statintr_4m(void *cap) | 183 | statintr_4m(void *cap) | |
159 | { | 184 | { | |
160 | struct clockframe *frame = cap; | 185 | struct clockframe *frame = cap; | |
161 | u_long newint; | 186 | u_long newint; | |
162 | 187 | |||
@@ -173,43 +198,39 @@ statintr_4m(void *cap) | @@ -173,43 +198,39 @@ statintr_4m(void *cap) | |||
173 | newint = new_interval(); | 198 | newint = new_interval(); | |
174 | 199 | |||
175 | /* | 200 | /* | |
176 | * Use the `non-resetting' limit register, so we don't | 201 | * Use the `non-resetting' limit register, so we don't | |
177 | * loose the counter ticks that happened since this | 202 | * loose the counter ticks that happened since this | |
178 | * interrupt was raised. | 203 | * interrupt was raised. | |
179 | */ | 204 | */ | |
180 | counterreg4m->t_limit_nr = tmr_ustolim4m(newint); | 205 | counterreg4m->t_limit_nr = tmr_ustolim4m(newint); | |
181 | 206 | |||
182 | /* | 207 | /* | |
183 | * The factor 8 is only valid for stathz==100. | 208 | * The factor 8 is only valid for stathz==100. | |
184 | * See also clock.c | 209 | * See also clock.c | |
185 | */ | 210 | */ | |
186 | #if !defined(MULTIPROCESSOR) | |||
187 | if ((++cpuinfo.ci_schedstate.spc_schedticks & 7) == 0 && schedhz != 0) { | 211 | if ((++cpuinfo.ci_schedstate.spc_schedticks & 7) == 0 && schedhz != 0) { | |
188 | #endif | |||
189 | if (CLKF_LOPRI(frame, IPL_SCHED)) { | 212 | if (CLKF_LOPRI(frame, IPL_SCHED)) { | |
190 | /* No need to schedule a soft interrupt */ | 213 | /* No need to schedule a soft interrupt */ | |
191 | spllowerschedclock(); | 214 | spllowerschedclock(); | |
192 | schedintr_4m(cap); | 215 | schedintr(cap); | |
193 | } else { | 216 | } else { | |
194 | /* | 217 | /* | |
195 | * We're interrupting a thread that may have the | 218 | * We're interrupting a thread that may have the | |
196 | * scheduler lock; run schedintr_4m() on this CPU later. | 219 | * scheduler lock; run schedintr() on this CPU later. | |
197 | */ | 220 | */ | |
198 | raise_ipi(&cpuinfo, IPL_SCHED); /* sched_cookie->pil */ | 221 | raise_ipi(&cpuinfo, IPL_SCHED); /* sched_cookie->pil */ | |
199 | } | 222 | } | |
200 | #if !defined(MULTIPROCESSOR) | |||
201 | } | 223 | } | |
202 | #endif | |||
203 | kpreempt_enable(); | 224 | kpreempt_enable(); | |
204 | 225 | |||
205 | return (1); | 226 | return (1); | |
206 | } | 227 | } | |
207 | 228 | |||
208 | void | 229 | void | |
209 | timerattach_obio_4m(device_t parent, device_t self, void *aux) | 230 | timerattach_obio_4m(device_t parent, device_t self, void *aux) | |
210 | { | 231 | { | |
211 | union obio_attach_args *uoba = aux; | 232 | union obio_attach_args *uoba = aux; | |
212 | struct sbus_attach_args *sa = &uoba->uoba_sbus; | 233 | struct sbus_attach_args *sa = &uoba->uoba_sbus; | |
213 | struct cpu_info *cpi; | 234 | struct cpu_info *cpi; | |
214 | bus_space_handle_t bh; | 235 | bus_space_handle_t bh; | |
215 | int i; | 236 | int i; | |
@@ -251,18 +272,34 @@ timerattach_obio_4m(device_t parent, dev | @@ -251,18 +272,34 @@ timerattach_obio_4m(device_t parent, dev | |||
251 | 272 | |||
252 | if (sbus_bus_map(sa->sa_bustag, | 273 | if (sbus_bus_map(sa->sa_bustag, | |
253 | sa->sa_reg[i].oa_space, | 274 | sa->sa_reg[i].oa_space, | |
254 | sa->sa_reg[i].oa_base, | 275 | sa->sa_reg[i].oa_base, | |
255 | sizeof(struct timer_4m), | 276 | sizeof(struct timer_4m), | |
256 | BUS_SPACE_MAP_LINEAR, | 277 | BUS_SPACE_MAP_LINEAR, | |
257 | &bh) != 0) { | 278 | &bh) != 0) { | |
258 | printf(": can't map CPU counter %d\n", i); | 279 | printf(": can't map CPU counter %d\n", i); | |
259 | return; | 280 | return; | |
260 | } | 281 | } | |
261 | cpi->counterreg_4m = (struct counter_4m *)bh; | 282 | cpi->counterreg_4m = (struct counter_4m *)bh; | |
262 | } | 283 | } | |
263 | 284 | |||
285 | #if defined(MULTIPROCESSOR) | |||
286 | if (sparc_ncpus > 1) { | |||
287 | /* | |||
288 | * Note that we don't actually use this cookie after checking | |||
289 | * it was establised, we call directly via raise_ipi() on | |||
290 | * IPL_HARDCLOCK. | |||
291 | */ | |||
292 | void *hardclock_cookie; | |||
293 | ||||
294 | hardclock_cookie = sparc_softintr_establish(IPL_HARDCLOCK, | |||
295 | hardclock_ipi, NULL); | |||
296 | if (hardclock_cookie == NULL) | |||
297 | panic("timerattach: cannot establish hardclock_intr"); | |||
298 | } | |||
299 | #endif | |||
300 | ||||
264 | /* Put processor counter in "timer" mode */ | 301 | /* Put processor counter in "timer" mode */ | |
265 | timerreg4m->t_cfg = 0; | 302 | timerreg4m->t_cfg = 0; | |
266 | 303 | |||
267 | timerattach(&timerreg4m->t_counter, &timerreg4m->t_limit); | 304 | timerattach(&timerreg4m->t_counter, &timerreg4m->t_limit); | |
268 | } | 305 | } |
--- src/sys/arch/sparc/sparc/timervar.h 2012/07/29 00:04:05 1.11
+++ src/sys/arch/sparc/sparc/timervar.h 2014/01/19 00:22:33 1.12
@@ -1,14 +1,14 @@ | @@ -1,14 +1,14 @@ | |||
1 | /* $NetBSD: timervar.h,v 1.11 2012/07/29 00:04:05 matt Exp $ */ | 1 | /* $NetBSD: timervar.h,v 1.12 2014/01/19 00:22:33 mrg Exp $ */ | |
2 | 2 | |||
3 | /* | 3 | /* | |
4 | * Copyright (c) 1992, 1993 | 4 | * Copyright (c) 1992, 1993 | |
5 | * The Regents of the University of California. All rights reserved. | 5 | * The Regents of the University of California. All rights reserved. | |
6 | * | 6 | * | |
7 | * This software was developed by the Computer Systems Engineering group | 7 | * This software was developed by the Computer Systems Engineering group | |
8 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | 8 | * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and | |
9 | * contributed to Berkeley. | 9 | * contributed to Berkeley. | |
10 | * | 10 | * | |
11 | * All advertising materials mentioning features or use of this software | 11 | * All advertising materials mentioning features or use of this software | |
12 | * must display the following acknowledgement: | 12 | * must display the following acknowledgement: | |
13 | * This product includes software developed by the University of | 13 | * This product includes software developed by the University of | |
14 | * California, Lawrence Berkeley Laboratory. | 14 | * California, Lawrence Berkeley Laboratory. | |
@@ -40,43 +40,42 @@ | @@ -40,43 +40,42 @@ | |||
40 | 40 | |||
41 | #include "opt_sparc_arch.h" | 41 | #include "opt_sparc_arch.h" | |
42 | 42 | |||
43 | #if defined(SUN4) || defined(SUN4C) | 43 | #if defined(SUN4) || defined(SUN4C) | |
44 | int clockintr_4(void *); | 44 | int clockintr_4(void *); | |
45 | int statintr_4(void *); | 45 | int statintr_4(void *); | |
46 | void timer_init_4(void); | 46 | void timer_init_4(void); | |
47 | 47 | |||
48 | void timerattach_obio_4(device_t, device_t, void *); | 48 | void timerattach_obio_4(device_t, device_t, void *); | |
49 | void timerattach_mainbus_4c(device_t, device_t, void *); | 49 | void timerattach_mainbus_4c(device_t, device_t, void *); | |
50 | #endif /* SUN4 || SUN4C */ | 50 | #endif /* SUN4 || SUN4C */ | |
51 | 51 | |||
52 | #if defined(SUN4M) | 52 | #if defined(SUN4M) | |
53 | void schedintr_4m(void *); | |||
54 | int clockintr_4m(void *); | 53 | int clockintr_4m(void *); | |
55 | int statintr_4m(void *); | 54 | int statintr_4m(void *); | |
56 | void timer_init_4m(void); | 55 | void timer_init_4m(void); | |
57 | 56 | |||
58 | void timerattach_obio_4m(device_t, device_t, void *); | 57 | void timerattach_obio_4m(device_t, device_t, void *); | |
59 | #endif /* SUN4M */ | 58 | #endif /* SUN4M */ | |
60 | 59 | |||
61 | /* Imported from clock.c: */ | 60 | /* Imported from clock.c: */ | |
62 | extern int statvar, statmin, statint; | 61 | extern int statvar, statmin, statint; | |
63 | extern int timerblurb; | 62 | extern int timerblurb; | |
64 | extern void (*timer_init)(void); | 63 | extern void (*timer_init)(void); | |
65 | extern void tickle_tc(void); | 64 | extern void tickle_tc(void); | |
66 | 65 | |||
67 | /* Common timer attach routine in timer.c: */ | 66 | /* Common timer attach routine in timer.c: */ | |
68 | void timerattach(volatile int *, volatile int *); | 67 | void timerattach(volatile int *, volatile int *); | |
69 | extern void *sched_cookie; /* for schedclock() interrupts */ | 68 | extern void *sched_cookie; /* for schedclock() interrupts */ | |
70 | 69 | |||
71 | static inline u_long __attribute__((__unused__)) | 70 | static inline u_long __attribute__((__unused__)) | |
72 | new_interval(void) | 71 | new_interval(void) | |
73 | { | 72 | { | |
74 | u_long newint, r, var; | 73 | u_long newint, r, var; | |
75 | 74 | |||
76 | /* | 75 | /* | |
77 | * Compute new randomized interval. The intervals are uniformly | 76 | * Compute new randomized interval. The intervals are uniformly | |
78 | * distributed on [statint - statvar / 2, statint + statvar / 2], | 77 | * distributed on [statint - statvar / 2, statint + statvar / 2], | |
79 | * and therefore have mean statint, giving a stathz frequency clock. | 78 | * and therefore have mean statint, giving a stathz frequency clock. | |
80 | */ | 79 | */ | |
81 | var = statvar; | 80 | var = statvar; | |
82 | do { | 81 | do { |