Deleted Added
full compact
kern_clocksource.c (210298) kern_clocksource.c (212541)
1/*-
2 * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
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

--- 11 unchanged lines hidden (view full) ---

20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2010 Alexander Motin <mav@FreeBSD.org>
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

--- 11 unchanged lines hidden (view full) ---

20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/kern/kern_clocksource.c 210298 2010-07-20 15:48:29Z mav $");
28__FBSDID("$FreeBSD: head/sys/kern/kern_clocksource.c 212541 2010-09-13 07:25:35Z mav $");
29
30/*
31 * Common routines to manage event timers hardware.
32 */
33
34/* XEN has own timer routines now. */
35#ifndef XEN
36
37#include "opt_kdtrace.h"
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/bus.h>
42#include <sys/lock.h>
43#include <sys/kdb.h>
29
30/*
31 * Common routines to manage event timers hardware.
32 */
33
34/* XEN has own timer routines now. */
35#ifndef XEN
36
37#include "opt_kdtrace.h"
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/bus.h>
42#include <sys/lock.h>
43#include <sys/kdb.h>
44#include <sys/ktr.h>
44#include <sys/mutex.h>
45#include <sys/proc.h>
46#include <sys/kernel.h>
47#include <sys/sched.h>
48#include <sys/smp.h>
49#include <sys/sysctl.h>
50#include <sys/timeet.h>
51
52#include <machine/atomic.h>
53#include <machine/clock.h>
54#include <machine/cpu.h>
55#include <machine/smp.h>
56
57#ifdef KDTRACE_HOOKS
58#include <sys/dtrace_bsd.h>
59cyclic_clock_func_t cyclic_clock_func[MAXCPU];
60#endif
61
45#include <sys/mutex.h>
46#include <sys/proc.h>
47#include <sys/kernel.h>
48#include <sys/sched.h>
49#include <sys/smp.h>
50#include <sys/sysctl.h>
51#include <sys/timeet.h>
52
53#include <machine/atomic.h>
54#include <machine/clock.h>
55#include <machine/cpu.h>
56#include <machine/smp.h>
57
58#ifdef KDTRACE_HOOKS
59#include <sys/dtrace_bsd.h>
60cyclic_clock_func_t cyclic_clock_func[MAXCPU];
61#endif
62
62static void cpu_restartclocks(void);
63static void timercheck(void);
64inline static int doconfigtimer(int i);
65static void configtimer(int i);
63int cpu_disable_deep_sleep = 0; /* Timer dies in C3. */
66
64
67static struct eventtimer *timer[2] = { NULL, NULL };
68static int timertest = 0;
69static int timerticks[2] = { 0, 0 };
70static int profiling_on = 0;
71static struct bintime timerperiod[2];
65static void setuptimer(void);
66static void loadtimer(struct bintime *now, int first);
67static int doconfigtimer(void);
68static void configtimer(int start);
69static int round_freq(struct eventtimer *et, int freq);
72
70
73static char timername[2][32];
74TUNABLE_STR("kern.eventtimer.timer1", timername[0], sizeof(*timername));
75TUNABLE_STR("kern.eventtimer.timer2", timername[1], sizeof(*timername));
71static void getnextcpuevent(struct bintime *event, int idle);
72static void getnextevent(struct bintime *event);
73static int handleevents(struct bintime *now, int fake);
74#ifdef SMP
75static void cpu_new_callout(int cpu, int ticks);
76#endif
76
77
77static u_int singlemul = 0;
78static struct mtx et_hw_mtx;
79
80#define ET_HW_LOCK(state) \
81 { \
82 if (timer->et_flags & ET_FLAGS_PERCPU) \
83 mtx_lock_spin(&(state)->et_hw_mtx); \
84 else \
85 mtx_lock_spin(&et_hw_mtx); \
86 }
87
88#define ET_HW_UNLOCK(state) \
89 { \
90 if (timer->et_flags & ET_FLAGS_PERCPU) \
91 mtx_unlock_spin(&(state)->et_hw_mtx); \
92 else \
93 mtx_unlock_spin(&et_hw_mtx); \
94 }
95
96static struct eventtimer *timer = NULL;
97static struct bintime timerperiod; /* Timer period for periodic mode. */
98static struct bintime hardperiod; /* hardclock() events period. */
99static struct bintime statperiod; /* statclock() events period. */
100static struct bintime profperiod; /* profclock() events period. */
101static struct bintime nexttick; /* Next global timer tick time. */
102static u_int busy = 0; /* Reconfiguration is in progress. */
103static int profiling = 0; /* Profiling events enabled. */
104
105static char timername[32]; /* Wanted timer. */
106TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername));
107
108static u_int singlemul = 0; /* Multiplier for periodic mode. */
78TUNABLE_INT("kern.eventtimer.singlemul", &singlemul);
79SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul,
109TUNABLE_INT("kern.eventtimer.singlemul", &singlemul);
110SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul,
80 0, "Multiplier, used in single timer mode");
111 0, "Multiplier for periodic mode");
81
112
82typedef u_int tc[2];
83static DPCPU_DEFINE(tc, configtimer);
113static u_int idletick = 0; /* Idle mode allowed. */
114TUNABLE_INT("kern.eventtimer.idletick", &idletick);
115SYSCTL_INT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RW, &idletick,
116 0, "Run periodic events when idle");
84
117
118static int periodic = 0; /* Periodic or one-shot mode. */
119TUNABLE_INT("kern.eventtimer.periodic", &periodic);
120
121struct pcpu_state {
122 struct mtx et_hw_mtx; /* Per-CPU timer mutex. */
123 u_int action; /* Reconfiguration requests. */
124 u_int handle; /* Immediate handle resuests. */
125 struct bintime now; /* Last tick time. */
126 struct bintime nextevent; /* Next scheduled event on this CPU. */
127 struct bintime nexttick; /* Next timer tick time. */
128 struct bintime nexthard; /* Next hardlock() event. */
129 struct bintime nextstat; /* Next statclock() event. */
130 struct bintime nextprof; /* Next profclock() event. */
131 int ipi; /* This CPU needs IPI. */
132 int idle; /* This CPU is in idle mode. */
133};
134
135static DPCPU_DEFINE(struct pcpu_state, timerstate);
136
85#define FREQ2BT(freq, bt) \
86{ \
87 (bt)->sec = 0; \
88 (bt)->frac = ((uint64_t)0x8000000000000000 / (freq)) << 1; \
89}
90#define BT2FREQ(bt) \
91 (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \
92 ((bt)->frac >> 1))
93
137#define FREQ2BT(freq, bt) \
138{ \
139 (bt)->sec = 0; \
140 (bt)->frac = ((uint64_t)0x8000000000000000 / (freq)) << 1; \
141}
142#define BT2FREQ(bt) \
143 (((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) / \
144 ((bt)->frac >> 1))
145
94/* Per-CPU timer1 handler. */
146/*
147 * Timer broadcast IPI handler.
148 */
149int
150hardclockintr(void)
151{
152 struct bintime now;
153 struct pcpu_state *state;
154 int done;
155
156 if (doconfigtimer() || busy)
157 return (FILTER_HANDLED);
158 state = DPCPU_PTR(timerstate);
159 now = state->now;
160 CTR4(KTR_SPARE2, "ipi at %d: now %d.%08x%08x",
161 curcpu, now.sec, (unsigned int)(now.frac >> 32),
162 (unsigned int)(now.frac & 0xffffffff));
163 done = handleevents(&now, 0);
164 return (done ? FILTER_HANDLED : FILTER_STRAY);
165}
166
167/*
168 * Handle all events for specified time on this CPU
169 */
95static int
170static int
96hardclockhandler(struct trapframe *frame)
171handleevents(struct bintime *now, int fake)
97{
172{
173 struct bintime t;
174 struct trapframe *frame;
175 struct pcpu_state *state;
176 uintfptr_t pc;
177 int usermode;
178 int done, runs;
98
179
180 CTR4(KTR_SPARE2, "handle at %d: now %d.%08x%08x",
181 curcpu, now->sec, (unsigned int)(now->frac >> 32),
182 (unsigned int)(now->frac & 0xffffffff));
183 done = 0;
184 if (fake) {
185 frame = NULL;
186 usermode = 0;
187 pc = 0;
188 } else {
189 frame = curthread->td_intr_frame;
190 usermode = TRAPF_USERMODE(frame);
191 pc = TRAPF_PC(frame);
192 }
99#ifdef KDTRACE_HOOKS
100 /*
101 * If the DTrace hooks are configured and a callback function
102 * has been registered, then call it to process the high speed
103 * timers.
104 */
193#ifdef KDTRACE_HOOKS
194 /*
195 * If the DTrace hooks are configured and a callback function
196 * has been registered, then call it to process the high speed
197 * timers.
198 */
105 int cpu = curcpu;
106 if (cyclic_clock_func[cpu] != NULL)
107 (*cyclic_clock_func[cpu])(frame);
199 if (!fake && cyclic_clock_func[curcpu] != NULL)
200 (*cyclic_clock_func[curcpu])(frame);
108#endif
201#endif
109
110 timer1clock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
111 return (FILTER_HANDLED);
202 runs = 0;
203 state = DPCPU_PTR(timerstate);
204 while (bintime_cmp(now, &state->nexthard, >=)) {
205 bintime_add(&state->nexthard, &hardperiod);
206 runs++;
207 }
208 if (runs) {
209 hardclock_anycpu(runs, usermode);
210 done = 1;
211 }
212 while (bintime_cmp(now, &state->nextstat, >=)) {
213 statclock(usermode);
214 bintime_add(&state->nextstat, &statperiod);
215 done = 1;
216 }
217 if (profiling) {
218 while (bintime_cmp(now, &state->nextprof, >=)) {
219 if (!fake)
220 profclock(usermode, pc);
221 bintime_add(&state->nextprof, &profperiod);
222 done = 1;
223 }
224 } else
225 state->nextprof = state->nextstat;
226 getnextcpuevent(&t, 0);
227 ET_HW_LOCK(state);
228 if (!busy) {
229 state->idle = 0;
230 state->nextevent = t;
231 loadtimer(now, 0);
232 }
233 ET_HW_UNLOCK(state);
234 return (done);
112}
113
235}
236
114/* Per-CPU timer2 handler. */
115static int
116statclockhandler(struct trapframe *frame)
237/*
238 * Schedule binuptime of the next event on current CPU.
239 */
240static void
241getnextcpuevent(struct bintime *event, int idle)
117{
242{
243 struct bintime tmp;
244 struct pcpu_state *state;
245 int skip;
118
246
119 timer2clock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
120 return (FILTER_HANDLED);
247 state = DPCPU_PTR(timerstate);
248 *event = state->nexthard;
249 if (idle) { /* If CPU is idle - ask callouts for how long. */
250 skip = callout_tickstofirst() - 1;
251 CTR2(KTR_SPARE2, "skip at %d: %d", curcpu, skip);
252 tmp = hardperiod;
253 bintime_mul(&tmp, skip);
254 bintime_add(event, &tmp);
255 } else { /* If CPU is active - handle all types of events. */
256 if (bintime_cmp(event, &state->nextstat, >))
257 *event = state->nextstat;
258 if (profiling &&
259 bintime_cmp(event, &state->nextprof, >))
260 *event = state->nextprof;
261 }
121}
122
262}
263
123/* timer1 broadcast IPI handler. */
124int
125hardclockintr(struct trapframe *frame)
126{
127
128 if (doconfigtimer(0))
129 return (FILTER_HANDLED);
130 return (hardclockhandler(frame));
131}
132
133/* timer2 broadcast IPI handler. */
134int
135statclockintr(struct trapframe *frame)
136{
137
138 if (doconfigtimer(1))
139 return (FILTER_HANDLED);
140 return (statclockhandler(frame));
141}
142
143/* timer1 callback. */
264/*
265 * Schedule binuptime of the next event on all CPUs.
266 */
144static void
267static void
145timer1cb(struct eventtimer *et, void *arg)
268getnextevent(struct bintime *event)
146{
269{
147
270 struct pcpu_state *state;
148#ifdef SMP
271#ifdef SMP
149 /* Broadcast interrupt to other CPUs for non-per-CPU timers */
150 if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0)
151 ipi_all_but_self(IPI_HARDCLOCK);
272 int cpu;
152#endif
273#endif
153 if (timertest) {
154 if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) {
155 timerticks[0]++;
156 if (timerticks[0] >= timer1hz) {
157 ET_LOCK();
158 timercheck();
159 ET_UNLOCK();
274 int c;
275
276 state = DPCPU_PTR(timerstate);
277 *event = state->nextevent;
278 c = curcpu;
279#ifdef SMP
280 if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) {
281 CPU_FOREACH(cpu) {
282 if (curcpu == cpu)
283 continue;
284 state = DPCPU_ID_PTR(cpu, timerstate);
285 if (bintime_cmp(event, &state->nextevent, >)) {
286 *event = state->nextevent;
287 c = cpu;
160 }
161 }
162 }
288 }
289 }
290 }
163 hardclockhandler(curthread->td_intr_frame);
291#endif
292 CTR5(KTR_SPARE2, "next at %d: next %d.%08x%08x by %d",
293 curcpu, event->sec, (unsigned int)(event->frac >> 32),
294 (unsigned int)(event->frac & 0xffffffff), c);
164}
165
295}
296
166/* timer2 callback. */
297/* Hardware timer callback function. */
167static void
298static void
168timer2cb(struct eventtimer *et, void *arg)
299timercb(struct eventtimer *et, void *arg)
169{
300{
301 struct bintime now;
302 struct bintime *next;
303 struct pcpu_state *state;
304#ifdef SMP
305 int cpu, bcast;
306#endif
170
307
308 /* Do not touch anything if somebody reconfiguring timers. */
309 if (busy)
310 return;
311 /* Update present and next tick times. */
312 state = DPCPU_PTR(timerstate);
313 if (et->et_flags & ET_FLAGS_PERCPU) {
314 next = &state->nexttick;
315 } else
316 next = &nexttick;
317 if (periodic) {
318 now = *next; /* Ex-next tick time becomes present time. */
319 bintime_add(next, &timerperiod); /* Next tick in 1 period. */
320 } else {
321 binuptime(&now); /* Get present time from hardware. */
322 next->sec = -1; /* Next tick is not scheduled yet. */
323 }
324 state->now = now;
325 CTR4(KTR_SPARE2, "intr at %d: now %d.%08x%08x",
326 curcpu, now.sec, (unsigned int)(now.frac >> 32),
327 (unsigned int)(now.frac & 0xffffffff));
328
171#ifdef SMP
329#ifdef SMP
172 /* Broadcast interrupt to other CPUs for non-per-CPU timers */
173 if (smp_started && (et->et_flags & ET_FLAGS_PERCPU) == 0)
174 ipi_all_but_self(IPI_STATCLOCK);
330 /* Prepare broadcasting to other CPUs for non-per-CPU timers. */
331 bcast = 0;
332 if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) {
333 CPU_FOREACH(cpu) {
334 if (curcpu == cpu)
335 continue;
336 state = DPCPU_ID_PTR(cpu, timerstate);
337 ET_HW_LOCK(state);
338 state->now = now;
339 if (bintime_cmp(&now, &state->nextevent, >=)) {
340 state->nextevent.sec++;
341 state->ipi = 1;
342 bcast = 1;
343 }
344 ET_HW_UNLOCK(state);
345 }
346 }
175#endif
347#endif
176 if (timertest) {
177 if ((et->et_flags & ET_FLAGS_PERCPU) == 0 || curcpu == 0) {
178 timerticks[1]++;
179 if (timerticks[1] >= timer2hz * 2) {
180 ET_LOCK();
181 timercheck();
182 ET_UNLOCK();
348
349 /* Handle events for this time on this CPU. */
350 handleevents(&now, 0);
351
352#ifdef SMP
353 /* Broadcast interrupt to other CPUs for non-per-CPU timers. */
354 if (bcast) {
355 CPU_FOREACH(cpu) {
356 if (curcpu == cpu)
357 continue;
358 state = DPCPU_ID_PTR(cpu, timerstate);
359 if (state->ipi) {
360 state->ipi = 0;
361 ipi_cpu(cpu, IPI_HARDCLOCK);
183 }
184 }
185 }
362 }
363 }
364 }
186 statclockhandler(curthread->td_intr_frame);
365#endif
187}
188
189/*
366}
367
368/*
190 * Check that both timers are running with at least 1/4 of configured rate.
191 * If not - replace the broken one.
369 * Load new value into hardware timer.
192 */
193static void
370 */
371static void
194timercheck(void)
372loadtimer(struct bintime *now, int start)
195{
373{
374 struct pcpu_state *state;
375 struct bintime new;
376 struct bintime *next;
377 uint64_t tmp;
378 int eq;
196
379
197 if (!timertest)
198 return;
199 timertest = 0;
200 if (timerticks[0] * 4 < timer1hz) {
201 printf("Event timer \"%s\" is dead.\n", timer[0]->et_name);
202 timer1hz = 0;
203 configtimer(0);
204 et_ban(timer[0]);
205 et_free(timer[0]);
206 timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
207 if (timer[0] == NULL) {
208 timer2hz = 0;
209 configtimer(1);
210 et_free(timer[1]);
211 timer[1] = NULL;
212 timer[0] = timer[1];
380 if (periodic) {
381 if (start) {
382 /*
383 * Try to start all periodic timers aligned
384 * to period to make events synchronous.
385 */
386 tmp = ((uint64_t)now->sec << 36) + (now->frac >> 28);
387 tmp = (tmp % (timerperiod.frac >> 28)) << 28;
388 tmp = timerperiod.frac - tmp;
389 new = timerperiod;
390 bintime_addx(&new, tmp);
391 CTR5(KTR_SPARE2, "load p at %d: now %d.%08x first in %d.%08x",
392 curcpu, now->sec, (unsigned int)(now->frac >> 32),
393 new.sec, (unsigned int)(new.frac >> 32));
394 et_start(timer, &new, &timerperiod);
213 }
395 }
214 et_init(timer[0], timer1cb, NULL, NULL);
215 cpu_restartclocks();
216 return;
396 } else {
397 if (timer->et_flags & ET_FLAGS_PERCPU) {
398 state = DPCPU_PTR(timerstate);
399 next = &state->nexttick;
400 } else
401 next = &nexttick;
402 getnextevent(&new);
403 eq = bintime_cmp(&new, next, ==);
404 CTR5(KTR_SPARE2, "load at %d: next %d.%08x%08x eq %d",
405 curcpu, new.sec, (unsigned int)(new.frac >> 32),
406 (unsigned int)(new.frac & 0xffffffff),
407 eq);
408 if (!eq) {
409 *next = new;
410 bintime_sub(&new, now);
411 et_start(timer, &new, NULL);
412 }
217 }
413 }
218 if (timerticks[1] * 4 < timer2hz) {
219 printf("Event timer \"%s\" is dead.\n", timer[1]->et_name);
220 timer2hz = 0;
221 configtimer(1);
222 et_ban(timer[1]);
223 et_free(timer[1]);
224 timer[1] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
225 if (timer[1] != NULL)
226 et_init(timer[1], timer2cb, NULL, NULL);
227 cpu_restartclocks();
228 return;
229 }
230}
231
232/*
414}
415
416/*
417 * Prepare event timer parameters after configuration changes.
418 */
419static void
420setuptimer(void)
421{
422 int freq;
423
424 if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0)
425 periodic = 0;
426 else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0)
427 periodic = 1;
428 freq = hz * singlemul;
429 while (freq < (profiling ? profhz : stathz))
430 freq += hz;
431 freq = round_freq(timer, freq);
432 FREQ2BT(freq, &timerperiod);
433}
434
435/*
233 * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler.
234 */
436 * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler.
437 */
235inline static int
236doconfigtimer(int i)
438static int
439doconfigtimer(void)
237{
440{
238 tc *conf;
441 struct bintime now;
442 struct pcpu_state *state;
239
443
240 conf = DPCPU_PTR(configtimer);
241 if (atomic_load_acq_int(*conf + i)) {
242 if (i == 0 ? timer1hz : timer2hz)
243 et_start(timer[i], NULL, &timerperiod[i]);
244 else
245 et_stop(timer[i]);
246 atomic_store_rel_int(*conf + i, 0);
444 state = DPCPU_PTR(timerstate);
445 switch (atomic_load_acq_int(&state->action)) {
446 case 1:
447 binuptime(&now);
448 ET_HW_LOCK(state);
449 loadtimer(&now, 1);
450 ET_HW_UNLOCK(state);
451 state->handle = 0;
452 atomic_store_rel_int(&state->action, 0);
247 return (1);
453 return (1);
454 case 2:
455 ET_HW_LOCK(state);
456 et_stop(timer);
457 ET_HW_UNLOCK(state);
458 state->handle = 0;
459 atomic_store_rel_int(&state->action, 0);
460 return (1);
248 }
461 }
462 if (atomic_readandclear_int(&state->handle) && !busy) {
463 binuptime(&now);
464 handleevents(&now, 0);
465 return (1);
466 }
249 return (0);
250}
251
252/*
253 * Reconfigure specified timer.
254 * For per-CPU timers use IPI to make other CPUs to reconfigure.
255 */
256static void
467 return (0);
468}
469
470/*
471 * Reconfigure specified timer.
472 * For per-CPU timers use IPI to make other CPUs to reconfigure.
473 */
474static void
257configtimer(int i)
475configtimer(int start)
258{
476{
259#ifdef SMP
260 tc *conf;
477 struct bintime now, next;
478 struct pcpu_state *state;
261 int cpu;
262
479 int cpu;
480
481 if (start) {
482 setuptimer();
483 binuptime(&now);
484 }
263 critical_enter();
485 critical_enter();
264#endif
265 /* Start/stop global timer or per-CPU timer of this CPU. */
266 if (i == 0 ? timer1hz : timer2hz)
267 et_start(timer[i], NULL, &timerperiod[i]);
268 else
269 et_stop(timer[i]);
486 ET_HW_LOCK(DPCPU_PTR(timerstate));
487 if (start) {
488 /* Initialize time machine parameters. */
489 next = now;
490 bintime_add(&next, &timerperiod);
491 if (periodic)
492 nexttick = next;
493 else
494 nexttick.sec = -1;
495 CPU_FOREACH(cpu) {
496 state = DPCPU_ID_PTR(cpu, timerstate);
497 state->now = now;
498 state->nextevent = next;
499 if (periodic)
500 state->nexttick = next;
501 else
502 state->nexttick.sec = -1;
503 state->nexthard = next;
504 state->nextstat = next;
505 state->nextprof = next;
506 hardclock_sync(cpu);
507 }
508 busy = 0;
509 /* Start global timer or per-CPU timer of this CPU. */
510 loadtimer(&now, 1);
511 } else {
512 busy = 1;
513 /* Stop global timer or per-CPU timer of this CPU. */
514 et_stop(timer);
515 }
516 ET_HW_UNLOCK(DPCPU_PTR(timerstate));
270#ifdef SMP
517#ifdef SMP
271 if ((timer[i]->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) {
518 /* If timer is global or there is no other CPUs yet - we are done. */
519 if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) {
272 critical_exit();
273 return;
274 }
275 /* Set reconfigure flags for other CPUs. */
276 CPU_FOREACH(cpu) {
520 critical_exit();
521 return;
522 }
523 /* Set reconfigure flags for other CPUs. */
524 CPU_FOREACH(cpu) {
277 conf = DPCPU_ID_PTR(cpu, configtimer);
278 atomic_store_rel_int(*conf + i, (cpu == curcpu) ? 0 : 1);
525 state = DPCPU_ID_PTR(cpu, timerstate);
526 atomic_store_rel_int(&state->action,
527 (cpu == curcpu) ? 0 : ( start ? 1 : 2));
279 }
528 }
280 /* Send reconfigure IPI. */
281 ipi_all_but_self(i == 0 ? IPI_HARDCLOCK : IPI_STATCLOCK);
529 /* Broadcast reconfigure IPI. */
530 ipi_all_but_self(IPI_HARDCLOCK);
282 /* Wait for reconfiguration completed. */
283restart:
284 cpu_spinwait();
285 CPU_FOREACH(cpu) {
286 if (cpu == curcpu)
287 continue;
531 /* Wait for reconfiguration completed. */
532restart:
533 cpu_spinwait();
534 CPU_FOREACH(cpu) {
535 if (cpu == curcpu)
536 continue;
288 conf = DPCPU_ID_PTR(cpu, configtimer);
289 if (atomic_load_acq_int(*conf + i))
537 state = DPCPU_ID_PTR(cpu, timerstate);
538 if (atomic_load_acq_int(&state->action))
290 goto restart;
291 }
539 goto restart;
540 }
292 critical_exit();
293#endif
541#endif
542 critical_exit();
294}
295
543}
544
545/*
546 * Calculate nearest frequency supported by hardware timer.
547 */
296static int
297round_freq(struct eventtimer *et, int freq)
298{
299 uint64_t div;
300
301 if (et->et_frequency != 0) {
302 div = lmax((et->et_frequency + freq / 2) / freq, 1);
303 if (et->et_flags & ET_FLAGS_POW2DIV)

--- 5 unchanged lines hidden (view full) ---

309 else if (et->et_min_period.frac != 0)
310 freq = min(freq, BT2FREQ(&et->et_min_period));
311 if (et->et_max_period.sec == 0 && et->et_max_period.frac != 0)
312 freq = max(freq, BT2FREQ(&et->et_max_period));
313 return (freq);
314}
315
316/*
548static int
549round_freq(struct eventtimer *et, int freq)
550{
551 uint64_t div;
552
553 if (et->et_frequency != 0) {
554 div = lmax((et->et_frequency + freq / 2) / freq, 1);
555 if (et->et_flags & ET_FLAGS_POW2DIV)

--- 5 unchanged lines hidden (view full) ---

561 else if (et->et_min_period.frac != 0)
562 freq = min(freq, BT2FREQ(&et->et_min_period));
563 if (et->et_max_period.sec == 0 && et->et_max_period.frac != 0)
564 freq = max(freq, BT2FREQ(&et->et_max_period));
565 return (freq);
566}
567
568/*
317 * Configure and start event timers.
569 * Configure and start event timers (BSP part).
318 */
319void
320cpu_initclocks_bsp(void)
321{
570 */
571void
572cpu_initclocks_bsp(void)
573{
322 int base, div;
574 struct pcpu_state *state;
575 int base, div, cpu;
323
576
324 timer[0] = et_find(timername[0], ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
325 if (timer[0] == NULL)
326 timer[0] = et_find(NULL, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
327 if (timer[0] == NULL)
577 mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN);
578 CPU_FOREACH(cpu) {
579 state = DPCPU_ID_PTR(cpu, timerstate);
580 mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN);
581 }
582#ifdef SMP
583 callout_new_inserted = cpu_new_callout;
584#endif
585 /* Grab requested timer or the best of present. */
586 if (timername[0])
587 timer = et_find(timername, 0, 0);
588 if (timer == NULL && periodic) {
589 timer = et_find(NULL,
590 ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
591 }
592 if (timer == NULL) {
593 timer = et_find(NULL,
594 ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT);
595 }
596 if (timer == NULL && !periodic) {
597 timer = et_find(NULL,
598 ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
599 }
600 if (timer == NULL)
328 panic("No usable event timer found!");
601 panic("No usable event timer found!");
329 et_init(timer[0], timer1cb, NULL, NULL);
330 timer[1] = et_find(timername[1][0] ? timername[1] : NULL,
331 ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
332 if (timer[1])
333 et_init(timer[1], timer2cb, NULL, NULL);
602 et_init(timer, timercb, NULL, NULL);
603
604 /* Adapt to timer capabilities. */
605 if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0)
606 periodic = 0;
607 else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0)
608 periodic = 1;
609 if (timer->et_flags & ET_FLAGS_C3STOP)
610 cpu_disable_deep_sleep++;
611
334 /*
335 * We honor the requested 'hz' value.
336 * We want to run stathz in the neighborhood of 128hz.
337 * We would like profhz to run as often as possible.
338 */
339 if (singlemul == 0) {
340 if (hz >= 1500 || (hz % 128) == 0)
341 singlemul = 1;
342 else if (hz >= 750)
343 singlemul = 2;
344 else
345 singlemul = 4;
346 }
612 /*
613 * We honor the requested 'hz' value.
614 * We want to run stathz in the neighborhood of 128hz.
615 * We would like profhz to run as often as possible.
616 */
617 if (singlemul == 0) {
618 if (hz >= 1500 || (hz % 128) == 0)
619 singlemul = 1;
620 else if (hz >= 750)
621 singlemul = 2;
622 else
623 singlemul = 4;
624 }
347 if (timer[1] == NULL) {
348 base = round_freq(timer[0], hz * singlemul);
625 if (periodic) {
626 base = round_freq(timer, hz * singlemul);
349 singlemul = max((base + hz / 2) / hz, 1);
350 hz = (base + singlemul / 2) / singlemul;
351 if (base <= 128)
352 stathz = base;
353 else {
354 div = base / 128;
355 if (div >= singlemul && (div % singlemul) == 0)
356 div++;
357 stathz = base / div;
358 }
359 profhz = stathz;
360 while ((profhz + stathz) <= 128 * 64)
361 profhz += stathz;
627 singlemul = max((base + hz / 2) / hz, 1);
628 hz = (base + singlemul / 2) / singlemul;
629 if (base <= 128)
630 stathz = base;
631 else {
632 div = base / 128;
633 if (div >= singlemul && (div % singlemul) == 0)
634 div++;
635 stathz = base / div;
636 }
637 profhz = stathz;
638 while ((profhz + stathz) <= 128 * 64)
639 profhz += stathz;
362 profhz = round_freq(timer[0], profhz);
640 profhz = round_freq(timer, profhz);
363 } else {
641 } else {
364 hz = round_freq(timer[0], hz);
365 stathz = round_freq(timer[1], 127);
366 profhz = round_freq(timer[1], stathz * 64);
642 hz = round_freq(timer, hz);
643 stathz = round_freq(timer, 127);
644 profhz = round_freq(timer, stathz * 64);
367 }
368 tick = 1000000 / hz;
645 }
646 tick = 1000000 / hz;
647 FREQ2BT(hz, &hardperiod);
648 FREQ2BT(stathz, &statperiod);
649 FREQ2BT(profhz, &profperiod);
369 ET_LOCK();
650 ET_LOCK();
370 cpu_restartclocks();
651 configtimer(1);
371 ET_UNLOCK();
372}
373
652 ET_UNLOCK();
653}
654
374/* Start per-CPU event timers on APs. */
655/*
656 * Start per-CPU event timers on APs.
657 */
375void
376cpu_initclocks_ap(void)
377{
658void
659cpu_initclocks_ap(void)
660{
661 struct bintime now;
662 struct pcpu_state *state;
378
663
379 ET_LOCK();
380 if (timer[0]->et_flags & ET_FLAGS_PERCPU)
381 et_start(timer[0], NULL, &timerperiod[0]);
382 if (timer[1] && timer[1]->et_flags & ET_FLAGS_PERCPU)
383 et_start(timer[1], NULL, &timerperiod[1]);
384 ET_UNLOCK();
664 if (timer->et_flags & ET_FLAGS_PERCPU) {
665 state = DPCPU_PTR(timerstate);
666 binuptime(&now);
667 ET_HW_LOCK(state);
668 loadtimer(&now, 1);
669 ET_HW_UNLOCK(state);
670 }
385}
386
671}
672
387/* Reconfigure and restart event timers after configuration changes. */
388static void
389cpu_restartclocks(void)
673/*
674 * Switch to profiling clock rates.
675 */
676void
677cpu_startprofclock(void)
390{
391
678{
679
392 /* Stop all event timers. */
393 timertest = 0;
394 if (timer1hz) {
395 timer1hz = 0;
680 ET_LOCK();
681 if (periodic) {
396 configtimer(0);
682 configtimer(0);
397 }
398 if (timer[1] && timer2hz) {
399 timer2hz = 0;
683 profiling = 1;
400 configtimer(1);
684 configtimer(1);
401 }
402 /* Calculate new event timers parameters. */
403 if (timer[1] == NULL) {
404 timer1hz = hz * singlemul;
405 while (timer1hz < (profiling_on ? profhz : stathz))
406 timer1hz += hz;
407 timer2hz = 0;
408 } else {
409 timer1hz = hz;
410 timer2hz = profiling_on ? profhz : stathz;
411 timer2hz = round_freq(timer[1], timer2hz);
412 }
413 timer1hz = round_freq(timer[0], timer1hz);
414 printf("Starting kernel event timers: %s @ %dHz, %s @ %dHz\n",
415 timer[0]->et_name, timer1hz,
416 timer[1] ? timer[1]->et_name : "NONE", timer2hz);
417 /* Restart event timers. */
418 FREQ2BT(timer1hz, &timerperiod[0]);
419 configtimer(0);
420 if (timer[1]) {
421 timerticks[0] = 0;
422 timerticks[1] = 0;
423 FREQ2BT(timer2hz, &timerperiod[1]);
424 configtimer(1);
425 timertest = 1;
426 }
685 } else
686 profiling = 1;
687 ET_UNLOCK();
427}
428
688}
689
429/* Switch to profiling clock rates. */
690/*
691 * Switch to regular clock rates.
692 */
430void
693void
431cpu_startprofclock(void)
694cpu_stopprofclock(void)
432{
433
434 ET_LOCK();
695{
696
697 ET_LOCK();
435 profiling_on = 1;
436 cpu_restartclocks();
698 if (periodic) {
699 configtimer(0);
700 profiling = 0;
701 configtimer(1);
702 } else
703 profiling = 0;
437 ET_UNLOCK();
438}
439
704 ET_UNLOCK();
705}
706
440/* Switch to regular clock rates. */
707/*
708 * Switch to idle mode (all ticks handled).
709 */
441void
710void
442cpu_stopprofclock(void)
711cpu_idleclock(void)
443{
712{
713 struct bintime now, t;
714 struct pcpu_state *state;
444
715
445 ET_LOCK();
446 profiling_on = 0;
447 cpu_restartclocks();
448 ET_UNLOCK();
716 if (idletick || busy ||
717 (periodic && (timer->et_flags & ET_FLAGS_PERCPU)))
718 return;
719 state = DPCPU_PTR(timerstate);
720 if (periodic)
721 now = state->now;
722 else
723 binuptime(&now);
724 CTR4(KTR_SPARE2, "idle at %d: now %d.%08x%08x",
725 curcpu, now.sec, (unsigned int)(now.frac >> 32),
726 (unsigned int)(now.frac & 0xffffffff));
727 getnextcpuevent(&t, 1);
728 ET_HW_LOCK(state);
729 state->idle = 1;
730 state->nextevent = t;
731 if (!periodic)
732 loadtimer(&now, 0);
733 ET_HW_UNLOCK(state);
449}
450
734}
735
451/* Report or change the active event timers hardware. */
736/*
737 * Switch to active mode (skip empty ticks).
738 */
739void
740cpu_activeclock(void)
741{
742 struct bintime now;
743 struct pcpu_state *state;
744 struct thread *td;
745
746 state = DPCPU_PTR(timerstate);
747 if (state->idle == 0 || busy)
748 return;
749 if (periodic)
750 now = state->now;
751 else
752 binuptime(&now);
753 CTR4(KTR_SPARE2, "active at %d: now %d.%08x%08x",
754 curcpu, now.sec, (unsigned int)(now.frac >> 32),
755 (unsigned int)(now.frac & 0xffffffff));
756 spinlock_enter();
757 td = curthread;
758 td->td_intr_nesting_level++;
759 handleevents(&now, 1);
760 td->td_intr_nesting_level--;
761 spinlock_exit();
762}
763
764#ifdef SMP
765static void
766cpu_new_callout(int cpu, int ticks)
767{
768 struct bintime tmp;
769 struct pcpu_state *state;
770
771 CTR3(KTR_SPARE2, "new co at %d: on %d in %d",
772 curcpu, cpu, ticks);
773 state = DPCPU_ID_PTR(cpu, timerstate);
774 ET_HW_LOCK(state);
775 if (state->idle == 0 || busy) {
776 ET_HW_UNLOCK(state);
777 return;
778 }
779 /*
780 * If timer is periodic - just update next event time for target CPU.
781 */
782 if (periodic) {
783 state->nextevent = state->nexthard;
784 tmp = hardperiod;
785 bintime_mul(&tmp, ticks - 1);
786 bintime_add(&state->nextevent, &tmp);
787 ET_HW_UNLOCK(state);
788 return;
789 }
790 /*
791 * Otherwise we have to wake that CPU up, as we can't get present
792 * bintime to reprogram global timer from here. If timer is per-CPU,
793 * we by definition can't do it from here.
794 */
795 ET_HW_UNLOCK(state);
796 if (timer->et_flags & ET_FLAGS_PERCPU) {
797 state->handle = 1;
798 ipi_cpu(cpu, IPI_HARDCLOCK);
799 } else {
800 if (!cpu_idle_wakeup(cpu))
801 ipi_cpu(cpu, IPI_AST);
802 }
803}
804#endif
805
806/*
807 * Report or change the active event timers hardware.
808 */
452static int
809static int
453sysctl_kern_eventtimer_timer1(SYSCTL_HANDLER_ARGS)
810sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS)
454{
455 char buf[32];
456 struct eventtimer *et;
457 int error;
458
459 ET_LOCK();
811{
812 char buf[32];
813 struct eventtimer *et;
814 int error;
815
816 ET_LOCK();
460 et = timer[0];
817 et = timer;
461 snprintf(buf, sizeof(buf), "%s", et->et_name);
462 ET_UNLOCK();
463 error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
464 ET_LOCK();
818 snprintf(buf, sizeof(buf), "%s", et->et_name);
819 ET_UNLOCK();
820 error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
821 ET_LOCK();
465 et = timer[0];
822 et = timer;
466 if (error != 0 || req->newptr == NULL ||
823 if (error != 0 || req->newptr == NULL ||
467 strcmp(buf, et->et_name) == 0) {
824 strcasecmp(buf, et->et_name) == 0) {
468 ET_UNLOCK();
469 return (error);
470 }
825 ET_UNLOCK();
826 return (error);
827 }
471 et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
828 et = et_find(buf, 0, 0);
472 if (et == NULL) {
473 ET_UNLOCK();
474 return (ENOENT);
475 }
829 if (et == NULL) {
830 ET_UNLOCK();
831 return (ENOENT);
832 }
476 timer1hz = 0;
477 configtimer(0);
833 configtimer(0);
478 et_free(timer[0]);
479 timer[0] = et;
480 et_init(timer[0], timer1cb, NULL, NULL);
481 cpu_restartclocks();
834 et_free(timer);
835 if (et->et_flags & ET_FLAGS_C3STOP)
836 cpu_disable_deep_sleep++;
837 if (timer->et_flags & ET_FLAGS_C3STOP)
838 cpu_disable_deep_sleep--;
839 timer = et;
840 et_init(timer, timercb, NULL, NULL);
841 configtimer(1);
482 ET_UNLOCK();
483 return (error);
484}
842 ET_UNLOCK();
843 return (error);
844}
485SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer1,
845SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer,
486 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
846 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
487 0, 0, sysctl_kern_eventtimer_timer1, "A", "Primary event timer");
847 0, 0, sysctl_kern_eventtimer_timer, "A", "Kernel event timer");
488
848
849/*
850 * Report or change the active event timer periodicity.
851 */
489static int
852static int
490sysctl_kern_eventtimer_timer2(SYSCTL_HANDLER_ARGS)
853sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS)
491{
854{
492 char buf[32];
493 struct eventtimer *et;
494 int error;
855 int error, val;
495
856
857 val = periodic;
858 error = sysctl_handle_int(oidp, &val, 0, req);
859 if (error != 0 || req->newptr == NULL)
860 return (error);
496 ET_LOCK();
861 ET_LOCK();
497 et = timer[1];
498 if (et == NULL)
499 snprintf(buf, sizeof(buf), "NONE");
500 else
501 snprintf(buf, sizeof(buf), "%s", et->et_name);
862 configtimer(0);
863 periodic = val;
864 configtimer(1);
502 ET_UNLOCK();
865 ET_UNLOCK();
503 error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
504 ET_LOCK();
505 et = timer[1];
506 if (error != 0 || req->newptr == NULL ||
507 strcmp(buf, et ? et->et_name : "NONE") == 0) {
508 ET_UNLOCK();
509 return (error);
510 }
511 et = et_find(buf, ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
512 if (et == NULL && strcasecmp(buf, "NONE") != 0) {
513 ET_UNLOCK();
514 return (ENOENT);
515 }
516 if (timer[1] != NULL) {
517 timer2hz = 0;
518 configtimer(1);
519 et_free(timer[1]);
520 }
521 timer[1] = et;
522 if (timer[1] != NULL)
523 et_init(timer[1], timer2cb, NULL, NULL);
524 cpu_restartclocks();
525 ET_UNLOCK();
526 return (error);
527}
866 return (error);
867}
528SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer2,
529 CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
530 0, 0, sysctl_kern_eventtimer_timer2, "A", "Secondary event timer");
868SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic,
869 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
870 0, 0, sysctl_kern_eventtimer_periodic, "I", "Kernel event timer periodic");
531
532#endif
871
872#endif
533