Add support for event timers whose clock frequency can change while running.
This commit is contained in:
parent
23e4da439c
commit
cfc4b56b57
@ -24,7 +24,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd February 25, 2013
|
||||
.Dd April 2, 2014
|
||||
.Dt EVENTTIMERS 9
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -68,6 +68,8 @@ struct eventtimer {
|
||||
.Fn et_register "struct eventtimer *et"
|
||||
.Ft int
|
||||
.Fn et_deregister "struct eventtimer *et"
|
||||
.Ft void
|
||||
.Fn et_change_frequency "struct eventtimer *et" "uint64_t newfreq"
|
||||
.Fn ET_LOCK
|
||||
.Fn ET_UNLOCK
|
||||
.Ft struct eventtimer *
|
||||
@ -176,6 +178,21 @@ methods control timers associated with the current CPU.
|
||||
.Pp
|
||||
Driver may deregister its functionality by calling
|
||||
.Fn et_deregister .
|
||||
.Pp
|
||||
If the frequency of the clock hardware can change while it is
|
||||
running (for example, during power-saving modes), the driver must call
|
||||
.Fn et_change_frequency
|
||||
on each change.
|
||||
If the given event timer is the active timer,
|
||||
.Fn et_change_frequency
|
||||
stops the timer on all CPUs, updates
|
||||
.Va et->frequency ,
|
||||
then restarts the timer on all CPUs so that all
|
||||
current events are rescheduled using the new frequency.
|
||||
If the given timer is not currently active,
|
||||
.Fn et_change_frequency
|
||||
simply updates
|
||||
.Va et->frequency .
|
||||
.Sh CONSUMER API
|
||||
.Fn et_find
|
||||
allows consumer to find available event timer, optionally matching specific
|
||||
|
@ -799,6 +799,25 @@ cpu_activeclock(void)
|
||||
spinlock_exit();
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the frequency of the given timer. This changes et->et_frequency and
|
||||
* if et is the active timer it reconfigures the timer on all CPUs. This is
|
||||
* intended to be a private interface for the use of et_change_frequency() only.
|
||||
*/
|
||||
void
|
||||
cpu_et_frequency(struct eventtimer *et, uint64_t newfreq)
|
||||
{
|
||||
|
||||
ET_LOCK();
|
||||
if (et == timer) {
|
||||
configtimer(0);
|
||||
et->et_frequency = newfreq;
|
||||
configtimer(1);
|
||||
} else
|
||||
et->et_frequency = newfreq;
|
||||
ET_UNLOCK();
|
||||
}
|
||||
|
||||
#ifdef KDTRACE_HOOKS
|
||||
void
|
||||
clocksource_cyc_set(const struct bintime *bt)
|
||||
|
@ -112,6 +112,18 @@ et_deregister(struct eventtimer *et)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the frequency of the given timer. If it is the active timer,
|
||||
* reconfigure it on all CPUs (reschedules all current events based on the new
|
||||
* timer frequency).
|
||||
*/
|
||||
void
|
||||
et_change_frequency(struct eventtimer *et, uint64_t newfreq)
|
||||
{
|
||||
|
||||
cpu_et_frequency(et, newfreq);
|
||||
}
|
||||
|
||||
/*
|
||||
* Find free event timer hardware with specified parameters.
|
||||
*/
|
||||
|
@ -168,6 +168,7 @@ struct ucred;
|
||||
struct uio;
|
||||
struct _jmp_buf;
|
||||
struct trapframe;
|
||||
struct eventtimer;
|
||||
|
||||
int setjmp(struct _jmp_buf *) __returns_twice;
|
||||
void longjmp(struct _jmp_buf *, int) __dead2;
|
||||
@ -286,6 +287,7 @@ void cpu_stopprofclock(void);
|
||||
sbintime_t cpu_idleclock(void);
|
||||
void cpu_activeclock(void);
|
||||
void cpu_new_callout(int cpu, sbintime_t bt, sbintime_t bt_opt);
|
||||
void cpu_et_frequency(struct eventtimer *et, uint64_t newfreq);
|
||||
extern int cpu_can_deep_sleep;
|
||||
extern int cpu_disable_deep_sleep;
|
||||
|
||||
|
@ -89,6 +89,7 @@ extern struct mtx et_eventtimers_mtx;
|
||||
/* Driver API */
|
||||
int et_register(struct eventtimer *et);
|
||||
int et_deregister(struct eventtimer *et);
|
||||
void et_change_frequency(struct eventtimer *et, uint64_t newfreq);
|
||||
/* Consumer API */
|
||||
struct eventtimer *et_find(const char *name, int check, int want);
|
||||
int et_init(struct eventtimer *et, et_event_cb_t *event,
|
||||
|
Loading…
Reference in New Issue
Block a user