Only use the interval timer for clock interrupts on the BSP and

have the BSP use IPIs to trigger clock interrupts on the APs.
This allows us to run on hardware configurations for which the
ITC has non-uniform frequencies across CPUs.

While here, change the clock XIV to type IPI so as to protect
the interrupt delivery against CPU re-balancing once that's
implemented.
This commit is contained in:
Marcel Moolenaar 2010-03-26 02:29:15 +00:00
parent 7482701cd4
commit f4926eabc2
3 changed files with 55 additions and 50 deletions

View file

@ -43,6 +43,7 @@ __FBSDID("$FreeBSD$");
#include <machine/intr.h>
#include <machine/intrcnt.h>
#include <machine/md_var.h>
#include <machine/smp.h>
SYSCTL_NODE(_debug, OID_AUTO, clock, CTLFLAG_RW, 0, "clock statistics");
@ -91,60 +92,63 @@ ia64_ih_clock(struct thread *td, u_int xiv, struct trapframe *tf)
int count;
PCPU_INC(md.stats.pcs_nclks);
intrcnt[INTRCNT_CLOCK]++;
itc = ia64_get_itc();
if (PCPU_GET(cpuid) == 0) {
/*
* Clock processing on the BSP.
*/
intrcnt[INTRCNT_CLOCK]++;
adj = PCPU_GET(md.clockadj);
clk = PCPU_GET(md.clock);
itc = ia64_get_itc();
delta = itc - clk;
count = 0;
while (delta >= ia64_clock_reload) {
/* Only the BSP runs the real clock */
if (PCPU_GET(cpuid) == 0)
adj = PCPU_GET(md.clockadj);
clk = PCPU_GET(md.clock);
delta = itc - clk;
count = 0;
while (delta >= ia64_clock_reload) {
#ifdef SMP
ipi_all_but_self(ia64_clock_xiv);
#endif
hardclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
else
hardclock_cpu(TRAPF_USERMODE(tf));
if (profprocs != 0)
profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
statclock(TRAPF_USERMODE(tf));
delta -= ia64_clock_reload;
clk += ia64_clock_reload;
if (adj != 0)
adjust_ticks++;
count++;
}
ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj);
ia64_srlz_d();
if (count > 0) {
adjust_lost += count - 1;
if (delta > (ia64_clock_reload >> 3)) {
if (adj == 0)
adjust_edges++;
adj = ia64_clock_reload >> 4;
} else
adj = 0;
} else {
adj = 0;
adjust_excess++;
}
PCPU_SET(md.clock, clk);
PCPU_SET(md.clockadj, adj);
} else {
/*
* Clock processing on the BSP.
*/
hardclock_cpu(TRAPF_USERMODE(tf));
if (profprocs != 0)
profclock(TRAPF_USERMODE(tf), TRAPF_PC(tf));
statclock(TRAPF_USERMODE(tf));
delta -= ia64_clock_reload;
clk += ia64_clock_reload;
if (adj != 0)
adjust_ticks++;
count++;
}
ia64_set_itm(ia64_get_itc() + ia64_clock_reload - adj);
ia64_srlz_d();
if (count > 0) {
adjust_lost += count - 1;
if (delta > (ia64_clock_reload >> 3)) {
if (adj == 0)
adjust_edges++;
adj = ia64_clock_reload >> 4;
} else
adj = 0;
} else {
adj = 0;
adjust_excess++;
}
PCPU_SET(md.clock, clk);
PCPU_SET(md.clockadj, adj);
return (0);
}
void
pcpu_initclock(void)
{
PCPU_SET(md.clockadj, 0);
PCPU_SET(md.clock, ia64_get_itc());
ia64_set_itm(PCPU_GET(md.clock) + ia64_clock_reload);
ia64_set_itv(ia64_clock_xiv);
ia64_srlz_d();
}
/*
* Start the real-time and statistics clocks. We use ar.itc and cr.itm
* to implement a 1000hz clock.
@ -154,7 +158,7 @@ cpu_initclocks()
{
u_long itc_freq;
ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IRQ,
ia64_clock_xiv = ia64_xiv_alloc(PI_REALTIME, IA64_XIV_IPI,
ia64_ih_clock);
if (ia64_clock_xiv == 0)
panic("No XIV for clock interrupts");
@ -169,7 +173,11 @@ cpu_initclocks()
tc_init(&ia64_timecounter);
#endif
pcpu_initclock();
PCPU_SET(md.clockadj, 0);
PCPU_SET(md.clock, ia64_get_itc());
ia64_set_itm(PCPU_GET(md.clock) + ia64_clock_reload);
ia64_set_itv(ia64_clock_xiv);
ia64_srlz_d();
}
void

View file

@ -206,9 +206,8 @@ ia64_ap_startup(void)
CTR1(KTR_SMP, "SMP: cpu%d launched", PCPU_GET(cpuid));
/* kick off the clock on this AP */
pcpu_initclock();
/* Mask interval timer interrupts on APs. */
ia64_set_itv(0x10000);
ia64_set_tpr(0);
ia64_srlz_d();
enable_intr();

View file

@ -91,8 +91,6 @@ __curthread(void)
#define PCPU_PTR(member) (&pcpup->pc_ ## member)
#define PCPU_SET(member,value) (pcpup->pc_ ## member = (value))
void pcpu_initclock(void);
#endif /* _KERNEL */
#endif /* !_MACHINE_PCPU_H_ */