diff --git a/sys/kern/kern_clocksource.c b/sys/kern/kern_clocksource.c --- a/sys/kern/kern_clocksource.c +++ b/sys/kern/kern_clocksource.c @@ -60,7 +60,7 @@ int cpu_disable_c3_sleep = 0; /* Timer dies in C3. */ static void setuptimer(void); -static void loadtimer(sbintime_t now, int first); +static sbintime_t loadtimer(int first); static int doconfigtimer(void); static void configtimer(int start); static int round_freq(struct eventtimer *et, int freq); @@ -219,7 +219,7 @@ if (!busy) { state->idle = 0; state->nextevent = t; - loadtimer(now, (fake == 2) && + loadtimer((fake == 2) && (timer->et_flags & ET_FLAGS_PERCPU)); } ET_HW_UNLOCK(state); @@ -371,22 +371,27 @@ } /* - * Load new value into hardware timer. + * Load new value into hardware timer and return + * the loaded time. */ -static void -loadtimer(sbintime_t now, int start) +static sbintime_t +loadtimer(int start) { + sbintime_t now; struct pcpu_state *state; sbintime_t new; sbintime_t *next; uint64_t tmp; - int eq; + bool eq; + + now = sbinuptime(); state = DPCPU_PTR(timerstate); if (timer->et_flags & ET_FLAGS_PERCPU) next = &state->nexttick; else next = &nexttick; + if (periodic) { if (start) { /* @@ -406,13 +411,15 @@ } else { new = getnextevent(state); eq = (new == *next); - CTR3(KTR_SPARE2, "load: next %d.%08x eq %d", + CTR5(KTR_SPARE2, "load: now %d.%08x first in %d.%08x eq %d", + (int)(now >> 32), (u_int)(now & 0xffffffff), (int)(new >> 32), (u_int)(new & 0xffffffff), eq); if (!eq) { *next = new; et_start(timer, new - now, 0); } } + return (*next - now); } /* @@ -447,9 +454,8 @@ state = DPCPU_PTR(timerstate); switch (atomic_load_acq_int(&state->action)) { case 1: - now = sbinuptime(); ET_HW_LOCK(state); - loadtimer(now, 1); + loadtimer(1); ET_HW_UNLOCK(state); state->handle = 0; atomic_store_rel_int(&state->action, 0); @@ -481,14 +487,13 @@ struct pcpu_state *state; int cpu; - if (start) { + if (start) setuptimer(); - now = sbinuptime(); - } else - now = 0; critical_enter(); ET_HW_LOCK(DPCPU_PTR(timerstate)); if (start) { + now = sbinuptime(); + /* Initialize time machine parameters. */ next = now + timerperiod; if (periodic) @@ -520,7 +525,7 @@ } busy = 0; /* Start global timer or per-CPU timer of this CPU. */ - loadtimer(now, 1); + loadtimer(1); } else { busy = 1; /* Stop global timer or per-CPU timer of this CPU. */ @@ -756,7 +761,7 @@ sbintime_t cpu_idleclock(void) { - sbintime_t now, t; + sbintime_t t; struct pcpu_state *state; if (idletick || busy || @@ -768,19 +773,17 @@ return (-1); state = DPCPU_PTR(timerstate); ET_HW_LOCK(state); - if (periodic) - now = state->now; - else - now = sbinuptime(); - CTR2(KTR_SPARE2, "idle: now %d.%08x", - (int)(now >> 32), (u_int)(now & 0xffffffff)); t = getnextcpuevent(state, 1); + CTR2(KTR_SPARE2, "idle: next %d.%08x", + (int)(t >> 32), (u_int)(t & 0xffffffff)); state->idle = 1; state->nextevent = t; - if (!periodic) - loadtimer(now, 0); + if (periodic) + t -= state->now; + else + t = loadtimer(0); ET_HW_UNLOCK(state); - return (MAX(t - now, 0)); + return (MAX(t, 0)); } /* @@ -866,7 +869,7 @@ goto done; /* If timer is global or of the current CPU -- reprogram it. */ if ((timer->et_flags & ET_FLAGS_PERCPU) == 0 || cpu == curcpu) { - loadtimer(sbinuptime(), 0); + loadtimer(0); done: ET_HW_UNLOCK(state); return;