kern_clocksource.c revision 212992
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
9 *    notice, this list of conditions and the following disclaimer,
10 *    without modification, immediately at the beginning of the file.
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.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
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 212992 2010-09-22 05:32:37Z 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_device_polling.h"
38#include "opt_kdtrace.h"
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/bus.h>
43#include <sys/lock.h>
44#include <sys/kdb.h>
45#include <sys/ktr.h>
46#include <sys/mutex.h>
47#include <sys/proc.h>
48#include <sys/kernel.h>
49#include <sys/sched.h>
50#include <sys/smp.h>
51#include <sys/sysctl.h>
52#include <sys/timeet.h>
53#include <sys/timetc.h>
54
55#include <machine/atomic.h>
56#include <machine/clock.h>
57#include <machine/cpu.h>
58#include <machine/smp.h>
59
60#ifdef KDTRACE_HOOKS
61#include <sys/dtrace_bsd.h>
62cyclic_clock_func_t	cyclic_clock_func[MAXCPU];
63#endif
64
65int			cpu_disable_deep_sleep = 0; /* Timer dies in C3. */
66
67static void		setuptimer(void);
68static void		loadtimer(struct bintime *now, int first);
69static int		doconfigtimer(void);
70static void		configtimer(int start);
71static int		round_freq(struct eventtimer *et, int freq);
72
73static void		getnextcpuevent(struct bintime *event, int idle);
74static void		getnextevent(struct bintime *event);
75static int		handleevents(struct bintime *now, int fake);
76#ifdef SMP
77static void		cpu_new_callout(int cpu, int ticks);
78#endif
79
80static struct mtx	et_hw_mtx;
81
82#define	ET_HW_LOCK(state)						\
83	{								\
84		if (timer->et_flags & ET_FLAGS_PERCPU)			\
85			mtx_lock_spin(&(state)->et_hw_mtx);		\
86		else							\
87			mtx_lock_spin(&et_hw_mtx);			\
88	}
89
90#define	ET_HW_UNLOCK(state)						\
91	{								\
92		if (timer->et_flags & ET_FLAGS_PERCPU)			\
93			mtx_unlock_spin(&(state)->et_hw_mtx);		\
94		else							\
95			mtx_unlock_spin(&et_hw_mtx);			\
96	}
97
98static struct eventtimer *timer = NULL;
99static struct bintime	timerperiod;	/* Timer period for periodic mode. */
100static struct bintime	hardperiod;	/* hardclock() events period. */
101static struct bintime	statperiod;	/* statclock() events period. */
102static struct bintime	profperiod;	/* profclock() events period. */
103static struct bintime	nexttick;	/* Next global timer tick time. */
104static u_int		busy = 0;	/* Reconfiguration is in progress. */
105static int		profiling = 0;	/* Profiling events enabled. */
106
107static char		timername[32];	/* Wanted timer. */
108TUNABLE_STR("kern.eventtimer.timer", timername, sizeof(timername));
109
110static int		singlemul = 0;	/* Multiplier for periodic mode. */
111TUNABLE_INT("kern.eventtimer.singlemul", &singlemul);
112SYSCTL_INT(_kern_eventtimer, OID_AUTO, singlemul, CTLFLAG_RW, &singlemul,
113    0, "Multiplier for periodic mode");
114
115static u_int		idletick = 0;	/* Idle mode allowed. */
116TUNABLE_INT("kern.eventtimer.idletick", &idletick);
117SYSCTL_INT(_kern_eventtimer, OID_AUTO, idletick, CTLFLAG_RW, &idletick,
118    0, "Run periodic events when idle");
119
120static int		periodic = 0;	/* Periodic or one-shot mode. */
121static int		want_periodic = 0; /* What mode to prefer. */
122TUNABLE_INT("kern.eventtimer.periodic", &want_periodic);
123
124struct pcpu_state {
125	struct mtx	et_hw_mtx;	/* Per-CPU timer mutex. */
126	u_int		action;		/* Reconfiguration requests. */
127	u_int		handle;		/* Immediate handle resuests. */
128	struct bintime	now;		/* Last tick time. */
129	struct bintime	nextevent;	/* Next scheduled event on this CPU. */
130	struct bintime	nexttick;	/* Next timer tick time. */
131	struct bintime	nexthard;	/* Next hardlock() event. */
132	struct bintime	nextstat;	/* Next statclock() event. */
133	struct bintime	nextprof;	/* Next profclock() event. */
134	int		ipi;		/* This CPU needs IPI. */
135	int		idle;		/* This CPU is in idle mode. */
136};
137
138static DPCPU_DEFINE(struct pcpu_state, timerstate);
139
140#define FREQ2BT(freq, bt)						\
141{									\
142	(bt)->sec = 0;							\
143	(bt)->frac = ((uint64_t)0x8000000000000000  / (freq)) << 1;	\
144}
145#define BT2FREQ(bt)							\
146	(((uint64_t)0x8000000000000000 + ((bt)->frac >> 2)) /		\
147	    ((bt)->frac >> 1))
148
149/*
150 * Timer broadcast IPI handler.
151 */
152int
153hardclockintr(void)
154{
155	struct bintime now;
156	struct pcpu_state *state;
157	int done;
158
159	if (doconfigtimer() || busy)
160		return (FILTER_HANDLED);
161	state = DPCPU_PTR(timerstate);
162	now = state->now;
163	CTR4(KTR_SPARE2, "ipi  at %d:    now  %d.%08x%08x",
164	    curcpu, now.sec, (unsigned int)(now.frac >> 32),
165			     (unsigned int)(now.frac & 0xffffffff));
166	done = handleevents(&now, 0);
167	return (done ? FILTER_HANDLED : FILTER_STRAY);
168}
169
170/*
171 * Handle all events for specified time on this CPU
172 */
173static int
174handleevents(struct bintime *now, int fake)
175{
176	struct bintime t;
177	struct trapframe *frame;
178	struct pcpu_state *state;
179	uintfptr_t pc;
180	int usermode;
181	int done, runs;
182
183	CTR4(KTR_SPARE2, "handle at %d:  now  %d.%08x%08x",
184	    curcpu, now->sec, (unsigned int)(now->frac >> 32),
185		     (unsigned int)(now->frac & 0xffffffff));
186	done = 0;
187	if (fake) {
188		frame = NULL;
189		usermode = 0;
190		pc = 0;
191	} else {
192		frame = curthread->td_intr_frame;
193		usermode = TRAPF_USERMODE(frame);
194		pc = TRAPF_PC(frame);
195	}
196#ifdef KDTRACE_HOOKS
197	/*
198	 * If the DTrace hooks are configured and a callback function
199	 * has been registered, then call it to process the high speed
200	 * timers.
201	 */
202	if (!fake && cyclic_clock_func[curcpu] != NULL)
203		(*cyclic_clock_func[curcpu])(frame);
204#endif
205	runs = 0;
206	state = DPCPU_PTR(timerstate);
207	while (bintime_cmp(now, &state->nexthard, >=)) {
208		bintime_add(&state->nexthard, &hardperiod);
209		runs++;
210	}
211	if (runs) {
212		hardclock_anycpu(runs, usermode);
213		done = 1;
214	}
215	while (bintime_cmp(now, &state->nextstat, >=)) {
216		statclock(usermode);
217		bintime_add(&state->nextstat, &statperiod);
218		done = 1;
219	}
220	if (profiling) {
221		while (bintime_cmp(now, &state->nextprof, >=)) {
222			if (!fake)
223				profclock(usermode, pc);
224			bintime_add(&state->nextprof, &profperiod);
225			done = 1;
226		}
227	} else
228		state->nextprof = state->nextstat;
229	getnextcpuevent(&t, 0);
230	ET_HW_LOCK(state);
231	if (!busy) {
232		state->idle = 0;
233		state->nextevent = t;
234		loadtimer(now, 0);
235	}
236	ET_HW_UNLOCK(state);
237	return (done);
238}
239
240/*
241 * Schedule binuptime of the next event on current CPU.
242 */
243static void
244getnextcpuevent(struct bintime *event, int idle)
245{
246	struct bintime tmp;
247	struct pcpu_state *state;
248	int skip;
249
250	state = DPCPU_PTR(timerstate);
251	*event = state->nexthard;
252	if (idle) { /* If CPU is idle - ask callouts for how long. */
253		skip = 4;
254		if (curcpu == CPU_FIRST() && tc_min_ticktock_freq > skip)
255			skip = tc_min_ticktock_freq;
256		skip = callout_tickstofirst(hz / skip) - 1;
257		CTR2(KTR_SPARE2, "skip   at %d: %d", curcpu, skip);
258		tmp = hardperiod;
259		bintime_mul(&tmp, skip);
260		bintime_add(event, &tmp);
261	} else { /* If CPU is active - handle all types of events. */
262		if (bintime_cmp(event, &state->nextstat, >))
263			*event = state->nextstat;
264		if (profiling &&
265		    bintime_cmp(event, &state->nextprof, >))
266			*event = state->nextprof;
267	}
268}
269
270/*
271 * Schedule binuptime of the next event on all CPUs.
272 */
273static void
274getnextevent(struct bintime *event)
275{
276	struct pcpu_state *state;
277#ifdef SMP
278	int	cpu;
279#endif
280	int	c;
281
282	state = DPCPU_PTR(timerstate);
283	*event = state->nextevent;
284	c = curcpu;
285#ifdef SMP
286	if ((timer->et_flags & ET_FLAGS_PERCPU) == 0) {
287		CPU_FOREACH(cpu) {
288			if (curcpu == cpu)
289				continue;
290			state = DPCPU_ID_PTR(cpu, timerstate);
291			if (bintime_cmp(event, &state->nextevent, >)) {
292				*event = state->nextevent;
293				c = cpu;
294			}
295		}
296	}
297#endif
298	CTR5(KTR_SPARE2, "next at %d:    next %d.%08x%08x by %d",
299	    curcpu, event->sec, (unsigned int)(event->frac >> 32),
300			     (unsigned int)(event->frac & 0xffffffff), c);
301}
302
303/* Hardware timer callback function. */
304static void
305timercb(struct eventtimer *et, void *arg)
306{
307	struct bintime now;
308	struct bintime *next;
309	struct pcpu_state *state;
310#ifdef SMP
311	int cpu, bcast;
312#endif
313
314	/* Do not touch anything if somebody reconfiguring timers. */
315	if (busy)
316		return;
317	/* Update present and next tick times. */
318	state = DPCPU_PTR(timerstate);
319	if (et->et_flags & ET_FLAGS_PERCPU) {
320		next = &state->nexttick;
321	} else
322		next = &nexttick;
323	if (periodic) {
324		now = *next;	/* Ex-next tick time becomes present time. */
325		bintime_add(next, &timerperiod); /* Next tick in 1 period. */
326	} else {
327		binuptime(&now);	/* Get present time from hardware. */
328		next->sec = -1;		/* Next tick is not scheduled yet. */
329	}
330	state->now = now;
331	CTR4(KTR_SPARE2, "intr at %d:    now  %d.%08x%08x",
332	    curcpu, now.sec, (unsigned int)(now.frac >> 32),
333			     (unsigned int)(now.frac & 0xffffffff));
334
335#ifdef SMP
336	/* Prepare broadcasting to other CPUs for non-per-CPU timers. */
337	bcast = 0;
338	if ((et->et_flags & ET_FLAGS_PERCPU) == 0 && smp_started) {
339		CPU_FOREACH(cpu) {
340			state = DPCPU_ID_PTR(cpu, timerstate);
341			ET_HW_LOCK(state);
342			state->now = now;
343			if (bintime_cmp(&now, &state->nextevent, >=)) {
344				state->nextevent.sec++;
345				if (curcpu != cpu) {
346					state->ipi = 1;
347					bcast = 1;
348				}
349			}
350			ET_HW_UNLOCK(state);
351		}
352	}
353#endif
354
355	/* Handle events for this time on this CPU. */
356	handleevents(&now, 0);
357
358#ifdef SMP
359	/* Broadcast interrupt to other CPUs for non-per-CPU timers. */
360	if (bcast) {
361		CPU_FOREACH(cpu) {
362			if (curcpu == cpu)
363				continue;
364			state = DPCPU_ID_PTR(cpu, timerstate);
365			if (state->ipi) {
366				state->ipi = 0;
367				ipi_cpu(cpu, IPI_HARDCLOCK);
368			}
369		}
370	}
371#endif
372}
373
374/*
375 * Load new value into hardware timer.
376 */
377static void
378loadtimer(struct bintime *now, int start)
379{
380	struct pcpu_state *state;
381	struct bintime new;
382	struct bintime *next;
383	uint64_t tmp;
384	int eq;
385
386	if (periodic) {
387		if (start) {
388			/*
389			 * Try to start all periodic timers aligned
390			 * to period to make events synchronous.
391			 */
392			tmp = ((uint64_t)now->sec << 36) + (now->frac >> 28);
393			tmp = (tmp % (timerperiod.frac >> 28)) << 28;
394			tmp = timerperiod.frac - tmp;
395			new = timerperiod;
396			bintime_addx(&new, tmp);
397			CTR5(KTR_SPARE2, "load p at %d:   now %d.%08x first in %d.%08x",
398			    curcpu, now->sec, (unsigned int)(now->frac >> 32),
399			    new.sec, (unsigned int)(new.frac >> 32));
400			et_start(timer, &new, &timerperiod);
401		}
402	} else {
403		if (timer->et_flags & ET_FLAGS_PERCPU) {
404			state = DPCPU_PTR(timerstate);
405			next = &state->nexttick;
406		} else
407			next = &nexttick;
408		getnextevent(&new);
409		eq = bintime_cmp(&new, next, ==);
410		CTR5(KTR_SPARE2, "load at %d:    next %d.%08x%08x eq %d",
411		    curcpu, new.sec, (unsigned int)(new.frac >> 32),
412			     (unsigned int)(new.frac & 0xffffffff),
413			     eq);
414		if (!eq) {
415			*next = new;
416			bintime_sub(&new, now);
417			et_start(timer, &new, NULL);
418		}
419	}
420}
421
422/*
423 * Prepare event timer parameters after configuration changes.
424 */
425static void
426setuptimer(void)
427{
428	int freq;
429
430	if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0)
431		periodic = 0;
432	else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0)
433		periodic = 1;
434	singlemul = MIN(MAX(singlemul, 1), 20);
435	freq = hz * singlemul;
436	while (freq < (profiling ? profhz : stathz))
437		freq += hz;
438	freq = round_freq(timer, freq);
439	FREQ2BT(freq, &timerperiod);
440}
441
442/*
443 * Reconfigure specified per-CPU timer on other CPU. Called from IPI handler.
444 */
445static int
446doconfigtimer(void)
447{
448	struct bintime now;
449	struct pcpu_state *state;
450
451	state = DPCPU_PTR(timerstate);
452	switch (atomic_load_acq_int(&state->action)) {
453	case 1:
454		binuptime(&now);
455		ET_HW_LOCK(state);
456		loadtimer(&now, 1);
457		ET_HW_UNLOCK(state);
458		state->handle = 0;
459		atomic_store_rel_int(&state->action, 0);
460		return (1);
461	case 2:
462		ET_HW_LOCK(state);
463		et_stop(timer);
464		ET_HW_UNLOCK(state);
465		state->handle = 0;
466		atomic_store_rel_int(&state->action, 0);
467		return (1);
468	}
469	if (atomic_readandclear_int(&state->handle) && !busy) {
470		binuptime(&now);
471		handleevents(&now, 0);
472		return (1);
473	}
474	return (0);
475}
476
477/*
478 * Reconfigure specified timer.
479 * For per-CPU timers use IPI to make other CPUs to reconfigure.
480 */
481static void
482configtimer(int start)
483{
484	struct bintime now, next;
485	struct pcpu_state *state;
486	int cpu;
487
488	if (start) {
489		setuptimer();
490		binuptime(&now);
491	}
492	critical_enter();
493	ET_HW_LOCK(DPCPU_PTR(timerstate));
494	if (start) {
495		/* Initialize time machine parameters. */
496		next = now;
497		bintime_add(&next, &timerperiod);
498		if (periodic)
499			nexttick = next;
500		else
501			nexttick.sec = -1;
502		CPU_FOREACH(cpu) {
503			state = DPCPU_ID_PTR(cpu, timerstate);
504			state->now = now;
505			state->nextevent = next;
506			if (periodic)
507				state->nexttick = next;
508			else
509				state->nexttick.sec = -1;
510			state->nexthard = next;
511			state->nextstat = next;
512			state->nextprof = next;
513			hardclock_sync(cpu);
514		}
515		busy = 0;
516		/* Start global timer or per-CPU timer of this CPU. */
517		loadtimer(&now, 1);
518	} else {
519		busy = 1;
520		/* Stop global timer or per-CPU timer of this CPU. */
521		et_stop(timer);
522	}
523	ET_HW_UNLOCK(DPCPU_PTR(timerstate));
524#ifdef SMP
525	/* If timer is global or there is no other CPUs yet - we are done. */
526	if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || !smp_started) {
527		critical_exit();
528		return;
529	}
530	/* Set reconfigure flags for other CPUs. */
531	CPU_FOREACH(cpu) {
532		state = DPCPU_ID_PTR(cpu, timerstate);
533		atomic_store_rel_int(&state->action,
534		    (cpu == curcpu) ? 0 : ( start ? 1 : 2));
535	}
536	/* Broadcast reconfigure IPI. */
537	ipi_all_but_self(IPI_HARDCLOCK);
538	/* Wait for reconfiguration completed. */
539restart:
540	cpu_spinwait();
541	CPU_FOREACH(cpu) {
542		if (cpu == curcpu)
543			continue;
544		state = DPCPU_ID_PTR(cpu, timerstate);
545		if (atomic_load_acq_int(&state->action))
546			goto restart;
547	}
548#endif
549	critical_exit();
550}
551
552/*
553 * Calculate nearest frequency supported by hardware timer.
554 */
555static int
556round_freq(struct eventtimer *et, int freq)
557{
558	uint64_t div;
559
560	if (et->et_frequency != 0) {
561		div = lmax((et->et_frequency + freq / 2) / freq, 1);
562		if (et->et_flags & ET_FLAGS_POW2DIV)
563			div = 1 << (flsl(div + div / 2) - 1);
564		freq = (et->et_frequency + div / 2) / div;
565	}
566	if (et->et_min_period.sec > 0)
567		freq = 0;
568	else if (et->et_min_period.frac != 0)
569		freq = min(freq, BT2FREQ(&et->et_min_period));
570	if (et->et_max_period.sec == 0 && et->et_max_period.frac != 0)
571		freq = max(freq, BT2FREQ(&et->et_max_period));
572	return (freq);
573}
574
575/*
576 * Configure and start event timers (BSP part).
577 */
578void
579cpu_initclocks_bsp(void)
580{
581	struct pcpu_state *state;
582	int base, div, cpu;
583
584	mtx_init(&et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN);
585	CPU_FOREACH(cpu) {
586		state = DPCPU_ID_PTR(cpu, timerstate);
587		mtx_init(&state->et_hw_mtx, "et_hw_mtx", NULL, MTX_SPIN);
588	}
589#ifdef SMP
590	callout_new_inserted = cpu_new_callout;
591#endif
592	periodic = want_periodic;
593	/* Grab requested timer or the best of present. */
594	if (timername[0])
595		timer = et_find(timername, 0, 0);
596	if (timer == NULL && periodic) {
597		timer = et_find(NULL,
598		    ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
599	}
600	if (timer == NULL) {
601		timer = et_find(NULL,
602		    ET_FLAGS_ONESHOT, ET_FLAGS_ONESHOT);
603	}
604	if (timer == NULL && !periodic) {
605		timer = et_find(NULL,
606		    ET_FLAGS_PERIODIC, ET_FLAGS_PERIODIC);
607	}
608	if (timer == NULL)
609		panic("No usable event timer found!");
610	et_init(timer, timercb, NULL, NULL);
611
612	/* Adapt to timer capabilities. */
613	if (periodic && (timer->et_flags & ET_FLAGS_PERIODIC) == 0)
614		periodic = 0;
615	else if (!periodic && (timer->et_flags & ET_FLAGS_ONESHOT) == 0)
616		periodic = 1;
617	if (timer->et_flags & ET_FLAGS_C3STOP)
618		cpu_disable_deep_sleep++;
619
620	/*
621	 * We honor the requested 'hz' value.
622	 * We want to run stathz in the neighborhood of 128hz.
623	 * We would like profhz to run as often as possible.
624	 */
625	if (singlemul <= 0 || singlemul > 20) {
626		if (hz >= 1500 || (hz % 128) == 0)
627			singlemul = 1;
628		else if (hz >= 750)
629			singlemul = 2;
630		else
631			singlemul = 4;
632	}
633	if (periodic) {
634		base = round_freq(timer, hz * singlemul);
635		singlemul = max((base + hz / 2) / hz, 1);
636		hz = (base + singlemul / 2) / singlemul;
637		if (base <= 128)
638			stathz = base;
639		else {
640			div = base / 128;
641			if (div >= singlemul && (div % singlemul) == 0)
642				div++;
643			stathz = base / div;
644		}
645		profhz = stathz;
646		while ((profhz + stathz) <= 128 * 64)
647			profhz += stathz;
648		profhz = round_freq(timer, profhz);
649	} else {
650		hz = round_freq(timer, hz);
651		stathz = round_freq(timer, 127);
652		profhz = round_freq(timer, stathz * 64);
653	}
654	tick = 1000000 / hz;
655	FREQ2BT(hz, &hardperiod);
656	FREQ2BT(stathz, &statperiod);
657	FREQ2BT(profhz, &profperiod);
658	ET_LOCK();
659	configtimer(1);
660	ET_UNLOCK();
661}
662
663/*
664 * Start per-CPU event timers on APs.
665 */
666void
667cpu_initclocks_ap(void)
668{
669	struct bintime now;
670	struct pcpu_state *state;
671
672	if (timer->et_flags & ET_FLAGS_PERCPU) {
673		state = DPCPU_PTR(timerstate);
674		binuptime(&now);
675		ET_HW_LOCK(state);
676		loadtimer(&now, 1);
677		ET_HW_UNLOCK(state);
678	}
679}
680
681/*
682 * Switch to profiling clock rates.
683 */
684void
685cpu_startprofclock(void)
686{
687
688	ET_LOCK();
689	if (periodic) {
690		configtimer(0);
691		profiling = 1;
692		configtimer(1);
693	} else
694		profiling = 1;
695	ET_UNLOCK();
696}
697
698/*
699 * Switch to regular clock rates.
700 */
701void
702cpu_stopprofclock(void)
703{
704
705	ET_LOCK();
706	if (periodic) {
707		configtimer(0);
708		profiling = 0;
709		configtimer(1);
710	} else
711		profiling = 0;
712	ET_UNLOCK();
713}
714
715/*
716 * Switch to idle mode (all ticks handled).
717 */
718void
719cpu_idleclock(void)
720{
721	struct bintime now, t;
722	struct pcpu_state *state;
723
724	if (idletick || busy ||
725	    (periodic && (timer->et_flags & ET_FLAGS_PERCPU))
726#ifdef DEVICE_POLLING
727	    || curcpu == CPU_FIRST()
728#endif
729	    )
730		return;
731	state = DPCPU_PTR(timerstate);
732	if (periodic)
733		now = state->now;
734	else
735		binuptime(&now);
736	CTR4(KTR_SPARE2, "idle at %d:    now  %d.%08x%08x",
737	    curcpu, now.sec, (unsigned int)(now.frac >> 32),
738			     (unsigned int)(now.frac & 0xffffffff));
739	getnextcpuevent(&t, 1);
740	ET_HW_LOCK(state);
741	state->idle = 1;
742	state->nextevent = t;
743	if (!periodic)
744		loadtimer(&now, 0);
745	ET_HW_UNLOCK(state);
746}
747
748/*
749 * Switch to active mode (skip empty ticks).
750 */
751void
752cpu_activeclock(void)
753{
754	struct bintime now;
755	struct pcpu_state *state;
756	struct thread *td;
757
758	state = DPCPU_PTR(timerstate);
759	if (state->idle == 0 || busy)
760		return;
761	if (periodic)
762		now = state->now;
763	else
764		binuptime(&now);
765	CTR4(KTR_SPARE2, "active at %d:  now  %d.%08x%08x",
766	    curcpu, now.sec, (unsigned int)(now.frac >> 32),
767			     (unsigned int)(now.frac & 0xffffffff));
768	spinlock_enter();
769	td = curthread;
770	td->td_intr_nesting_level++;
771	handleevents(&now, 1);
772	td->td_intr_nesting_level--;
773	spinlock_exit();
774}
775
776#ifdef SMP
777static void
778cpu_new_callout(int cpu, int ticks)
779{
780	struct bintime tmp;
781	struct pcpu_state *state;
782
783	CTR3(KTR_SPARE2, "new co at %d:    on %d in %d",
784	    curcpu, cpu, ticks);
785	state = DPCPU_ID_PTR(cpu, timerstate);
786	ET_HW_LOCK(state);
787	if (state->idle == 0 || busy) {
788		ET_HW_UNLOCK(state);
789		return;
790	}
791	/*
792	 * If timer is periodic - just update next event time for target CPU.
793	 * If timer is global - there is chance it is already programmed.
794	 */
795	if (periodic || (timer->et_flags & ET_FLAGS_PERCPU) == 0) {
796		state->nextevent = state->nexthard;
797		tmp = hardperiod;
798		bintime_mul(&tmp, ticks - 1);
799		bintime_add(&state->nextevent, &tmp);
800		if (periodic ||
801		    bintime_cmp(&state->nextevent, &nexttick, >=)) {
802			ET_HW_UNLOCK(state);
803			return;
804		}
805	}
806	/*
807	 * Otherwise we have to wake that CPU up, as we can't get present
808	 * bintime to reprogram global timer from here. If timer is per-CPU,
809	 * we by definition can't do it from here.
810	 */
811	ET_HW_UNLOCK(state);
812	if (timer->et_flags & ET_FLAGS_PERCPU) {
813		state->handle = 1;
814		ipi_cpu(cpu, IPI_HARDCLOCK);
815	} else {
816		if (!cpu_idle_wakeup(cpu))
817			ipi_cpu(cpu, IPI_AST);
818	}
819}
820#endif
821
822/*
823 * Report or change the active event timers hardware.
824 */
825static int
826sysctl_kern_eventtimer_timer(SYSCTL_HANDLER_ARGS)
827{
828	char buf[32];
829	struct eventtimer *et;
830	int error;
831
832	ET_LOCK();
833	et = timer;
834	snprintf(buf, sizeof(buf), "%s", et->et_name);
835	ET_UNLOCK();
836	error = sysctl_handle_string(oidp, buf, sizeof(buf), req);
837	ET_LOCK();
838	et = timer;
839	if (error != 0 || req->newptr == NULL ||
840	    strcasecmp(buf, et->et_name) == 0) {
841		ET_UNLOCK();
842		return (error);
843	}
844	et = et_find(buf, 0, 0);
845	if (et == NULL) {
846		ET_UNLOCK();
847		return (ENOENT);
848	}
849	configtimer(0);
850	et_free(timer);
851	if (et->et_flags & ET_FLAGS_C3STOP)
852		cpu_disable_deep_sleep++;
853	if (timer->et_flags & ET_FLAGS_C3STOP)
854		cpu_disable_deep_sleep--;
855	periodic = want_periodic;
856	timer = et;
857	et_init(timer, timercb, NULL, NULL);
858	configtimer(1);
859	ET_UNLOCK();
860	return (error);
861}
862SYSCTL_PROC(_kern_eventtimer, OID_AUTO, timer,
863    CTLTYPE_STRING | CTLFLAG_RW | CTLFLAG_MPSAFE,
864    0, 0, sysctl_kern_eventtimer_timer, "A", "Chosen event timer");
865
866/*
867 * Report or change the active event timer periodicity.
868 */
869static int
870sysctl_kern_eventtimer_periodic(SYSCTL_HANDLER_ARGS)
871{
872	int error, val;
873
874	val = periodic;
875	error = sysctl_handle_int(oidp, &val, 0, req);
876	if (error != 0 || req->newptr == NULL)
877		return (error);
878	ET_LOCK();
879	configtimer(0);
880	periodic = want_periodic = val;
881	configtimer(1);
882	ET_UNLOCK();
883	return (error);
884}
885SYSCTL_PROC(_kern_eventtimer, OID_AUTO, periodic,
886    CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_MPSAFE,
887    0, 0, sysctl_kern_eventtimer_periodic, "I", "Enable event timer periodic mode");
888
889#endif
890