summaryrefslogtreecommitdiffstats
path: root/sys/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'sys/amd64')
-rw-r--r--sys/amd64/amd64/local_apic.c71
-rw-r--r--sys/amd64/include/apicvar.h8
-rw-r--r--sys/amd64/isa/clock.c15
3 files changed, 58 insertions, 36 deletions
diff --git a/sys/amd64/amd64/local_apic.c b/sys/amd64/amd64/local_apic.c
index 98ed4df..0d04bbd 100644
--- a/sys/amd64/amd64/local_apic.c
+++ b/sys/amd64/amd64/local_apic.c
@@ -160,6 +160,9 @@ static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
struct pic lapic_pic = { .pic_resume = lapic_resume };
+static int lapic_allclocks;
+TUNABLE_INT("machdep.lapic_allclocks", &lapic_allclocks);
+
static uint32_t
lvt_mode(struct lapic *la, u_int pin, uint32_t value)
{
@@ -415,10 +418,11 @@ lapic_disable_pmc(void)
/*
* Called by cpu_initclocks() on the BSP to setup the local APIC timer so
* that it can drive hardclock, statclock, and profclock. This function
- * returns true if it is able to use the local APIC timer to drive the
- * clocks and false if it is not able.
+ * returns a positive integer if it is convenient to use the local APIC
+ * for all the clocks, a negative integer if it is convenient to use the
+ * local APIC only for the hardclock and 0 if none of them can be handled.
*/
-int
+enum lapic_clock
lapic_setup_clock(void)
{
u_long value;
@@ -426,10 +430,10 @@ lapic_setup_clock(void)
/* Can't drive the timer without a local APIC. */
if (lapic == NULL)
- return (0);
+ return (LAPIC_CLOCK_NONE);
if (resource_int_value("apic", 0, "clock", &i) == 0 && i == 0)
- return (0);
+ return (LAPIC_CLOCK_NONE);
/* Start off with a divisor of 2 (power on reset default). */
lapic_timer_divisor = 2;
@@ -461,19 +465,27 @@ lapic_setup_clock(void)
* (and profhz) run at hz. If 'hz' is below 1500 but above
* 750, then we let the lapic timer run at 2 * 'hz'. If 'hz'
* is below 750 then we let the lapic timer run at 4 * 'hz'.
+ *
+ * Please note that stathz and profhz are set only if all the
+ * clocks are handled through the local APIC.
*/
- if (hz >= 1500)
+ if (lapic_allclocks != 0) {
+ if (hz >= 1500)
+ lapic_timer_hz = hz;
+ else if (hz >= 750)
+ lapic_timer_hz = hz * 2;
+ else
+ lapic_timer_hz = hz * 4;
+ } else
lapic_timer_hz = hz;
- else if (hz >= 750)
- lapic_timer_hz = hz * 2;
- else
- lapic_timer_hz = hz * 4;
- if (lapic_timer_hz < 128)
- stathz = lapic_timer_hz;
- else
- stathz = lapic_timer_hz / (lapic_timer_hz / 128);
- profhz = lapic_timer_hz;
lapic_timer_period = value / lapic_timer_hz;
+ if (lapic_allclocks != 0) {
+ if (lapic_timer_hz < 128)
+ stathz = lapic_timer_hz;
+ else
+ stathz = lapic_timer_hz / (lapic_timer_hz / 128);
+ profhz = lapic_timer_hz;
+ }
/*
* Start up the timer on the BSP. The APs will kick off their
@@ -481,7 +493,7 @@ lapic_setup_clock(void)
*/
lapic_timer_periodic(lapic_timer_period);
lapic_timer_enable_intr();
- return (1);
+ return (lapic_allclocks == 0 ? LAPIC_CLOCK_HARDCLOCK : LAPIC_CLOCK_ALL);
}
void
@@ -784,20 +796,23 @@ lapic_handle_timer(struct trapframe *frame)
else
hardclock_cpu(TRAPF_USERMODE(frame));
}
+ if (lapic_allclocks != 0) {
- /* Fire statclock at stathz. */
- la->la_stat_ticks += stathz;
- if (la->la_stat_ticks >= lapic_timer_hz) {
- la->la_stat_ticks -= lapic_timer_hz;
- statclock(TRAPF_USERMODE(frame));
- }
+ /* Fire statclock at stathz. */
+ la->la_stat_ticks += stathz;
+ if (la->la_stat_ticks >= lapic_timer_hz) {
+ la->la_stat_ticks -= lapic_timer_hz;
+ statclock(TRAPF_USERMODE(frame));
+ }
- /* Fire profclock at profhz, but only when needed. */
- la->la_prof_ticks += profhz;
- if (la->la_prof_ticks >= lapic_timer_hz) {
- la->la_prof_ticks -= lapic_timer_hz;
- if (profprocs != 0)
- profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame));
+ /* Fire profclock at profhz, but only when needed. */
+ la->la_prof_ticks += profhz;
+ if (la->la_prof_ticks >= lapic_timer_hz) {
+ la->la_prof_ticks -= lapic_timer_hz;
+ if (profprocs != 0)
+ profclock(TRAPF_USERMODE(frame),
+ TRAPF_PC(frame));
+ }
}
critical_exit();
}
diff --git a/sys/amd64/include/apicvar.h b/sys/amd64/include/apicvar.h
index 9d6d538..8f15d84 100644
--- a/sys/amd64/include/apicvar.h
+++ b/sys/amd64/include/apicvar.h
@@ -157,6 +157,12 @@
#define APIC_BUS_PCI 2
#define APIC_BUS_MAX APIC_BUS_PCI
+enum lapic_clock {
+ LAPIC_CLOCK_NONE,
+ LAPIC_CLOCK_HARDCLOCK,
+ LAPIC_CLOCK_ALL
+};
+
/*
* An APIC enumerator is a psuedo bus driver that enumerates APIC's including
* CPU's and I/O APIC's.
@@ -224,7 +230,7 @@ int lapic_set_lvt_triggermode(u_int apic_id, u_int lvt,
enum intr_trigger trigger);
void lapic_set_tpr(u_int vector);
void lapic_setup(int boot);
-int lapic_setup_clock(void);
+enum lapic_clock lapic_setup_clock(void);
#endif /* !LOCORE */
#endif /* _MACHINE_APICVAR_H_ */
diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c
index adc1743..bf379f3 100644
--- a/sys/amd64/isa/clock.c
+++ b/sys/amd64/isa/clock.c
@@ -91,7 +91,7 @@ static u_int32_t i8254_offset;
static int (*i8254_pending)(struct intsrc *);
static int i8254_ticked;
static int using_atrtc_timer;
-static int using_lapic_timer;
+static enum lapic_clock using_lapic_timer = LAPIC_CLOCK_NONE;
/* Values for timerX_state: */
#define RELEASED 0
@@ -160,7 +160,8 @@ clkintr(struct trapframe *frame)
clkintr_pending = 0;
mtx_unlock_spin(&clock_lock);
}
- KASSERT(!using_lapic_timer, ("clk interrupt enabled with lapic timer"));
+ KASSERT(using_lapic_timer == LAPIC_CLOCK_NONE,
+ ("clk interrupt enabled with lapic timer"));
if (using_atrtc_timer) {
#ifdef SMP
@@ -422,7 +423,7 @@ set_i8254_freq(u_int freq, int intr_freq)
i8254_timecounter.tc_frequency = freq;
mtx_lock_spin(&clock_lock);
i8254_freq = freq;
- if (using_lapic_timer)
+ if (using_lapic_timer != LAPIC_CLOCK_NONE)
new_i8254_real_max_count = 0x10000;
else
new_i8254_real_max_count = TIMER_DIV(intr_freq);
@@ -485,7 +486,7 @@ cpu_initclocks()
* that it can drive hardclock(). Otherwise, change the 8254
* timecounter to user a simpler algorithm.
*/
- if (!using_lapic_timer) {
+ if (using_lapic_timer == LAPIC_CLOCK_NONE) {
intr_add_handler("clk", 0, (driver_filter_t *)clkintr, NULL,
NULL, INTR_TYPE_CLK, NULL);
i8254_intsrc = intr_lookup_source(0);
@@ -508,7 +509,7 @@ cpu_initclocks()
* kernel clocks, then setup the RTC to periodically interrupt to
* drive statclock() and profclock().
*/
- if (!using_lapic_timer) {
+ if (using_lapic_timer != LAPIC_CLOCK_ALL) {
using_atrtc_timer = atrtc_setup_clock();
if (using_atrtc_timer) {
/* Enable periodic interrupts from the RTC. */
@@ -532,7 +533,7 @@ void
cpu_startprofclock(void)
{
- if (using_lapic_timer || !using_atrtc_timer)
+ if (using_lapic_timer == LAPIC_CLOCK_ALL || !using_atrtc_timer)
return;
atrtc_rate(RTCSA_PROF);
psdiv = pscnt = psratio;
@@ -542,7 +543,7 @@ void
cpu_stopprofclock(void)
{
- if (using_lapic_timer || !using_atrtc_timer)
+ if (using_lapic_timer == LAPIC_CLOCK_ALL || !using_atrtc_timer)
return;
atrtc_rate(RTCSA_NOPROF);
psdiv = pscnt = 1;
OpenPOWER on IntegriCloud