summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--sys/conf/options.i3861
-rw-r--r--sys/i386/i386/local_apic.c79
-rw-r--r--sys/i386/include/apicvar.h8
-rw-r--r--sys/i386/isa/clock.c15
-rw-r--r--sys/pc98/cbus/clock.c9
8 files changed, 129 insertions, 77 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;
diff --git a/sys/conf/options.i386 b/sys/conf/options.i386
index cd2ab98..83f8286 100644
--- a/sys/conf/options.i386
+++ b/sys/conf/options.i386
@@ -105,6 +105,7 @@ NETGRAPH_CRONYX opt_ng_cronyx.h
# Device options
DEV_APIC opt_apic.h
+DEV_ATPIC opt_atpic.h
DEV_NPX opt_npx.h
ASR_COMPAT opt_asr.h
diff --git a/sys/i386/i386/local_apic.c b/sys/i386/i386/local_apic.c
index 1451ec8..e0049c8 100644
--- a/sys/i386/i386/local_apic.c
+++ b/sys/i386/i386/local_apic.c
@@ -34,6 +34,7 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_atpic.h"
#include "opt_hwpmc_hooks.h"
#include "opt_kdtrace.h"
@@ -160,6 +161,17 @@ static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value);
struct pic lapic_pic = { .pic_resume = lapic_resume };
+/*
+ * The atrtc device is compiled in only if atpic is present.
+ * If it is not, force lapic to take care of all the clocks.
+ */
+#ifdef DEV_ATPIC
+static int lapic_allclocks;
+TUNABLE_INT("machdep.lapic_allclocks", &lapic_allclocks);
+#else
+static int lapic_allclocks = 1;
+#endif
+
static uint32_t
lvt_mode(struct lapic *la, u_int pin, uint32_t value)
{
@@ -416,11 +428,9 @@ 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.
+ * that it can drive hardclock, statclock, and profclock.
*/
-int
+enum lapic_clock
lapic_setup_clock(void)
{
u_long value;
@@ -428,10 +438,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;
@@ -463,19 +473,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
@@ -483,7 +501,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
@@ -786,20 +804,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/i386/include/apicvar.h b/sys/i386/include/apicvar.h
index b15452b..2f8e716 100644
--- a/sys/i386/include/apicvar.h
+++ b/sys/i386/include/apicvar.h
@@ -186,6 +186,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.
@@ -253,7 +259,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/i386/isa/clock.c b/sys/i386/isa/clock.c
index 12e76e4..1549b17 100644
--- a/sys/i386/isa/clock.c
+++ b/sys/i386/isa/clock.c
@@ -106,7 +106,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
@@ -175,7 +175,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"));
#ifdef KDTRACE_HOOKS
/*
@@ -453,7 +454,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);
@@ -533,7 +534,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);
@@ -556,7 +557,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. */
@@ -580,7 +581,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;
@@ -590,7 +591,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;
diff --git a/sys/pc98/cbus/clock.c b/sys/pc98/cbus/clock.c
index bb651bd..7300593 100644
--- a/sys/pc98/cbus/clock.c
+++ b/sys/pc98/cbus/clock.c
@@ -101,7 +101,7 @@ static u_int32_t i8254_lastcount;
static u_int32_t i8254_offset;
static int (*i8254_pending)(struct intsrc *);
static int i8254_ticked;
-static int using_lapic_timer;
+static enum lapic_clock using_lapic_timer = LAPIC_CLOCK_NONE;
/* Values for timerX_state: */
#define RELEASED 0
@@ -164,7 +164,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"));
#ifdef KDTRACE_HOOKS
/*
@@ -360,7 +361,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);
@@ -443,7 +444,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);
OpenPOWER on IntegriCloud