Simplify clock interrupt handling on mips by using the new KPI - timer1clock()

and timer2clock().

Dynamically adjust the tick frequency depending on the value of 'hz'. Tested
with hz values of 100, 1000 and 2000.
This commit is contained in:
Neel Natu 2010-05-27 01:27:25 +00:00
parent 0e85f214e3
commit 87164cbbaa
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=208585

View File

@ -58,19 +58,12 @@ struct timecounter *platform_timecounter;
static uint64_t cycles_per_tick;
static uint64_t cycles_per_usec;
static uint64_t cycles_per_hz, cycles_per_stathz, cycles_per_profhz;
static u_int32_t counter_upper = 0;
static u_int32_t counter_lower_last = 0;
struct clk_ticks {
u_long hard_ticks;
u_long stat_ticks;
u_long prof_ticks;
uint32_t compare_ticks;
} __aligned(CACHE_LINE_SIZE);
static struct clk_ticks pcpu_ticks[MAXCPU];
static DPCPU_DEFINE(uint32_t, compare_ticks);
static DPCPU_DEFINE(uint32_t, lost_ticks);
/*
* Device methods
@ -150,22 +143,23 @@ mips_timer_init_params(uint64_t platform_counter_freq, int double_count)
if (double_count != 0)
counter_freq /= 2;
cycles_per_tick = counter_freq / 1000;
cycles_per_hz = counter_freq / hz;
cycles_per_stathz = counter_freq / stathz;
cycles_per_profhz = counter_freq / profhz;
if (hz >= 1500)
timer1hz = hz;
else if (hz >= 750)
timer1hz = hz * 2;
else
timer1hz = hz * 4;
cycles_per_tick = counter_freq / timer1hz;
cycles_per_usec = counter_freq / (1 * 1000 * 1000);
counter_timecounter.tc_frequency = counter_freq;
printf("hz=%d cyl_per_tick:%jd cyl_per_usec:%jd freq:%jd "
"cyl_per_hz:%jd cyl_per_stathz:%jd cyl_per_profhz:%jd\n",
printf("hz=%d timer1hz:%d cyl_per_tick:%jd cyl_per_usec:%jd freq:%jd\n",
hz,
timer1hz,
cycles_per_tick,
cycles_per_usec,
counter_freq,
cycles_per_hz,
cycles_per_stathz,
cycles_per_profhz);
counter_freq);
set_cputicker(tick_ticker, counter_freq, 1);
}
@ -243,58 +237,59 @@ DELAY(int n)
}
}
#if 0 /* TARGET_OCTEON */
int64_t wheel_run = 0;
void octeon_led_run_wheel();
#endif
/*
* Device section of file below
*/
static int
clock_intr(void *arg)
{
struct clk_ticks *cpu_ticks;
struct trapframe *tf;
uint32_t count, compare, delta;
cpu_ticks = &pcpu_ticks[PCPU_GET(cpuid)];
uint32_t count, compare_last, compare_next, lost_ticks;
/*
* Set next clock edge.
*/
count = mips_rd_count();
compare = cpu_ticks->compare_ticks;
cpu_ticks->compare_ticks = count + cycles_per_tick;
mips_wr_compare(cpu_ticks->compare_ticks);
compare_last = DPCPU_GET(compare_ticks);
compare_next = count + cycles_per_tick;
DPCPU_SET(compare_ticks, compare_next);
mips_wr_compare(compare_next);
critical_enter();
if (count < counter_lower_last) {
counter_upper++;
counter_lower_last = count;
}
/*
* Magic. Setting up with an arg of NULL means we get passed tf.
*/
tf = (struct trapframe *)arg;
delta = cycles_per_tick;
/*
* Account for the "lost time" between when the timer interrupt fired
* and when 'clock_intr' actually started executing.
*/
delta += count - compare;
lost_ticks = DPCPU_GET(lost_ticks);
lost_ticks += count - compare_last;
/*
* If the COUNT and COMPARE registers are no longer in sync then make
* up some reasonable value for the 'delta'.
* up some reasonable value for the 'lost_ticks'.
*
* This could happen, for e.g., after we resume normal operations after
* exiting the debugger.
*/
if (delta > cycles_per_hz)
delta = cycles_per_hz;
if (lost_ticks > 2 * cycles_per_tick)
lost_ticks = cycles_per_tick;
while (lost_ticks >= cycles_per_tick) {
timer1clock(TRAPF_USERMODE(tf), tf->pc);
timer2clock(TRAPF_USERMODE(tf), tf->pc);
lost_ticks -= cycles_per_tick;
}
DPCPU_SET(lost_ticks, lost_ticks);
#ifdef KDTRACE_HOOKS
/*
* If the DTrace hooks are configured and a callback function
@ -305,39 +300,9 @@ clock_intr(void *arg)
if (cyclic_clock_func[cpu] != NULL)
(*cyclic_clock_func[cpu])(tf);
#endif
/* Fire hardclock at hz. */
cpu_ticks->hard_ticks += delta;
if (cpu_ticks->hard_ticks >= cycles_per_hz) {
cpu_ticks->hard_ticks -= cycles_per_hz;
if (PCPU_GET(cpuid) == 0)
hardclock(TRAPF_USERMODE(tf), tf->pc);
else
hardclock_cpu(TRAPF_USERMODE(tf));
}
/* Fire statclock at stathz. */
cpu_ticks->stat_ticks += delta;
if (cpu_ticks->stat_ticks >= cycles_per_stathz) {
cpu_ticks->stat_ticks -= cycles_per_stathz;
statclock(TRAPF_USERMODE(tf));
}
/* Fire profclock at profhz, but only when needed. */
cpu_ticks->prof_ticks += delta;
if (cpu_ticks->prof_ticks >= cycles_per_profhz) {
cpu_ticks->prof_ticks -= cycles_per_profhz;
if (profprocs != 0)
profclock(TRAPF_USERMODE(tf), tf->pc);
}
timer1clock(TRAPF_USERMODE(tf), tf->pc);
timer2clock(TRAPF_USERMODE(tf), tf->pc);
critical_exit();
#if 0 /* TARGET_OCTEON */
/* Run the FreeBSD display once every hz ticks */
wheel_run += cycles_per_tick;
if (wheel_run >= cycles_per_usec * 1000000ULL) {
wheel_run = 0;
octeon_led_run_wheel();
}
#endif
return (FILTER_HANDLED);
}