Created
May 1, 2010 02:58
-
-
Save oza/386004 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From e5e403e2cc772dac3e0472f1d6d81f777d6df36f Mon Sep 17 00:00:00 2001 | |
From: OZAWA Tsuyoshi <[email protected]> | |
Date: Tue, 4 May 2010 21:19:32 +0900 | |
Subject: [PATCH] add i386 & amd64 support | |
Signed-off-by: OZAWA Tsuyoshi <[email protected]> | |
--- | |
sys/amd64/amd64/apic_vector.S | 2 +- | |
sys/amd64/amd64/local_apic.c | 123 +++++++++++++++++++++++++++++++++++++++++ | |
sys/amd64/isa/clock.c | 13 ++++- | |
sys/amd64/isa/dynticks.c | 81 +++++++++++++++++++++++++++ | |
sys/conf/files.amd64 | 1 + | |
sys/conf/files.i386 | 1 + | |
sys/i386/i386/apic_vector.s | 2 +- | |
sys/i386/i386/local_apic.c | 120 ++++++++++++++++++++++++++++++++++++++++ | |
sys/i386/isa/clock.c | 18 +++++- | |
sys/i386/isa/dynticks.c | 120 ++++++++++++++++++++++++++++++++++++++++ | |
sys/kern/kern_clock.c | 27 +++++++++ | |
sys/kern/kern_timeout.c | 28 +++++++++ | |
sys/kern/sched_4bsd.c | 3 + | |
sys/kern/sched_ule.c | 3 + | |
sys/sys/dynticks.h | 49 ++++++++++++++++ | |
sys/sys/systm.h | 1 + | |
16 files changed, 587 insertions(+), 5 deletions(-) | |
create mode 100644 sys/amd64/isa/dynticks.c | |
create mode 100644 sys/i386/isa/dynticks.c | |
create mode 100644 sys/sys/dynticks.h | |
diff --git a/sys/amd64/amd64/apic_vector.S b/sys/amd64/amd64/apic_vector.S | |
index 7aa2891..7609ae4 100644 | |
--- a/sys/amd64/amd64/apic_vector.S | |
+++ b/sys/amd64/amd64/apic_vector.S | |
@@ -100,7 +100,7 @@ IDTVEC(timerint) | |
PUSH_FRAME | |
FAKE_MCOUNT(TF_RIP(%rsp)) | |
movq %rsp, %rdi | |
- call lapic_handle_timer | |
+ call timer_intr_handler | |
MEXITCOUNT | |
jmp doreti | |
diff --git a/sys/amd64/amd64/local_apic.c b/sys/amd64/amd64/local_apic.c | |
index 79be51e..3ba823d 100644 | |
--- a/sys/amd64/amd64/local_apic.c | |
+++ b/sys/amd64/amd64/local_apic.c | |
@@ -66,6 +66,8 @@ __FBSDID("$FreeBSD: src/sys/amd64/amd64/local_apic.c,v 1.42.2.7.2.1 2010/02/10 0 | |
#include <ddb/ddb.h> | |
#endif | |
+#include <sys/dynticks.h> | |
+ | |
#ifdef KDTRACE_HOOKS | |
#include <sys/dtrace_bsd.h> | |
cyclic_clock_func_t lapic_cyclic_clock_func[MAXCPU]; | |
@@ -109,6 +111,9 @@ struct lapic { | |
u_long la_hard_ticks; | |
u_long la_stat_ticks; | |
u_long la_prof_ticks; | |
+ u_long la_last_tick; | |
+ u_long la_cur_skip; | |
+ u_long la_skip; | |
} static lapics[MAX_APIC_ID + 1]; | |
/* XXX: should thermal be an NMI? */ | |
@@ -142,6 +147,7 @@ static u_int32_t lapic_timer_divisors[] = { | |
APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128 | |
}; | |
+ | |
extern inthand_t IDTVEC(rsvd); | |
volatile lapic_t *lapic; | |
@@ -156,6 +162,9 @@ static void lapic_timer_periodic(u_int count); | |
static void lapic_timer_set_divisor(u_int divisor); | |
static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value); | |
+static struct timer_ops lapic_ops; | |
+static void lapic_handle_timer_dynamically(struct trapframe *frame); | |
+ | |
struct pic lapic_pic = { .pic_resume = lapic_resume }; | |
static uint32_t | |
@@ -488,6 +497,8 @@ lapic_setup_clock(void) | |
profhz = lapic_timer_hz; | |
lapic_timer_period = value / lapic_timer_hz; | |
+ register_timer_intr_handlers(&lapic_ops); | |
+ | |
/* | |
* Start up the timer on the BSP. The APs will kick off their | |
* timer during lapic_setup(). | |
@@ -799,6 +810,10 @@ lapic_handle_timer(struct trapframe *frame) | |
if (profprocs != 0) | |
profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); | |
} | |
+ | |
+ la->la_cur_skip = 0; | |
+ la->la_skip = 1; | |
+ | |
critical_exit(); | |
} | |
@@ -1325,3 +1340,111 @@ lapic_ipi_vectored(u_int vector, int dest) | |
#endif /* DETECT_DEADLOCK */ | |
} | |
#endif /* SMP */ | |
+ | |
+ | |
+ | |
+static void lapic_set_next_timer_intr(void) | |
+{ | |
+ struct lapic *la; | |
+ int skip; | |
+ u_long cnt_to_skip; | |
+ | |
+ la = &lapics[PCPU_GET(apic_id)]; | |
+ (*la->la_timer_count)++; | |
+ | |
+ skip = callout_get_next_event(); | |
+ cnt_to_skip = lapic_timer_period * skip ; | |
+ lapic_timer_oneshot(cnt_to_skip); | |
+ la->la_skip = skip; | |
+ la->la_cur_skip = 0; | |
+ | |
+ return; | |
+} | |
+ | |
+static void lapic_set_timer_periodic(void) | |
+{ | |
+ lapic_timer_periodic(lapic_timer_period); | |
+} | |
+ | |
+static void | |
+lapic_handle_timer_dynamically(struct trapframe *frame) | |
+{ | |
+ struct lapic *la; | |
+ int skip; | |
+ int i; | |
+ | |
+ /* Send EOI first thing. */ | |
+ lapic_eoi(); | |
+ | |
+#if defined(SMP) && !defined(SCHED_ULE) | |
+ /* | |
+ * Don't do any accounting for the disabled HTT cores, since it | |
+ * will provide misleading numbers for the userland. | |
+ * | |
+ * No locking is necessary here, since even if we loose the race | |
+ * when hlt_cpus_mask changes it is not a big deal, really. | |
+ * | |
+ * Don't do that for ULE, since ULE doesn't consider hlt_cpus_mask | |
+ * and unlike other schedulers it actually schedules threads to | |
+ * those CPUs. | |
+ */ | |
+ if ((hlt_cpus_mask & (1 << PCPU_GET(cpuid))) != 0) | |
+ return; | |
+#endif | |
+ | |
+ /* Look up our local APIC structure for the tick counters. */ | |
+ la = &lapics[PCPU_GET(apic_id)]; | |
+ (*la->la_timer_count)++; | |
+ critical_enter(); | |
+ | |
+#ifdef KDTRACE_HOOKS | |
+ /* | |
+ * If the DTrace hooks are configured and a callback function | |
+ * has been registered, then call it to process the high speed | |
+ * timers. | |
+ */ | |
+ int cpu = PCPU_GET(cpuid); | |
+ /* i dont know this works well? */ | |
+ if (lapic_cyclic_clock_func[cpu] != NULL) | |
+ (*lapic_cyclic_clock_func[cpu])(frame); | |
+#endif | |
+ /* Fire hardclock at hz. */ | |
+ skip = la->la_skip; | |
+ for(i = 0; i < skip; i++){ | |
+ la->la_hard_ticks += hz; | |
+ if (la->la_hard_ticks >= lapic_timer_hz) { | |
+ la->la_hard_ticks -= lapic_timer_hz; | |
+ if (PCPU_GET(cpuid) == 0) | |
+ hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); | |
+ else | |
+ hardclock_cpu(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) { | |
+ if (profprocs != 0){ | |
+ la->la_prof_ticks -= lapic_timer_hz; | |
+ profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); | |
+ } | |
+ } | |
+ } | |
+ | |
+ lapic_set_next_timer_intr(); | |
+ critical_exit(); | |
+} | |
+ | |
+ | |
+static struct timer_ops lapic_ops = { | |
+ .perticks_handler = lapic_handle_timer, | |
+ .dynticks_handler = lapic_handle_timer_dynamically, | |
+ .set_timer_periodic = lapic_set_timer_periodic, | |
+ .set_next_timer_intr = lapic_set_next_timer_intr, | |
+}; | |
diff --git a/sys/amd64/isa/clock.c b/sys/amd64/isa/clock.c | |
index d8b48d2..4aaf2c8 100644 | |
--- a/sys/amd64/isa/clock.c | |
+++ b/sys/amd64/isa/clock.c | |
@@ -69,6 +69,7 @@ __FBSDID("$FreeBSD: src/sys/amd64/isa/clock.c,v 1.234.2.2.6.1 2010/02/10 00:26:2 | |
#include <sys/sysctl.h> | |
#include <sys/cons.h> | |
#include <sys/power.h> | |
+#include <sys/dynticks.h> | |
#include <machine/clock.h> | |
#include <machine/cpu.h> | |
@@ -134,6 +135,8 @@ static unsigned i8254_get_timecount(struct timecounter *tc); | |
static unsigned i8254_simple_get_timecount(struct timecounter *tc); | |
static void set_timer_freq(u_int freq, int intr_freq); | |
+static struct timer_ops clk_ops; | |
+ | |
static struct timecounter i8254_timecounter = { | |
i8254_get_timecount, /* get_timecount */ | |
0, /* no poll_pps */ | |
@@ -765,7 +768,8 @@ cpu_initclocks() | |
* timecounter to user a simpler algorithm. | |
*/ | |
if (!using_lapic_timer) { | |
- intr_add_handler("clk", 0, (driver_filter_t *)clkintr, NULL, NULL, | |
+ register_timer_intr_handlers(&clk_ops); | |
+ intr_add_handler("clk", 0, (driver_filter_t *)timer_intr_handler, NULL, NULL, | |
INTR_TYPE_CLK, NULL); | |
i8254_intsrc = intr_lookup_source(0); | |
if (i8254_intsrc != NULL) | |
@@ -935,4 +939,11 @@ static devclass_t attimer_devclass; | |
DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0); | |
DRIVER_MODULE(attimer, acpi, attimer_driver, attimer_devclass, 0, 0); | |
+static struct timer_ops clk_ops = { | |
+ .ext_perticks_handler = clkintr, | |
+ .ext_dynticks_handler = NULL, | |
+ .set_next_timer_intr = NULL, | |
+ .set_timer_periodic = NULL, | |
+}; | |
+ | |
#endif /* DEV_ISA */ | |
diff --git a/sys/amd64/isa/dynticks.c b/sys/amd64/isa/dynticks.c | |
new file mode 100644 | |
index 0000000..7ae8f8b | |
--- /dev/null | |
+++ b/sys/amd64/isa/dynticks.c | |
@@ -0,0 +1,81 @@ | |
+/*- | |
+ * Copyright (c) 2003 OZAWA Tsuyoshi <[email protected]> | |
+ * All rights reserved. | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * 3. Neither the name of the author nor the names of any co-contributors | |
+ * may be used to endorse or promote products derived from this software | |
+ * without specific prior written permission. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
+ * SUCH DAMAGE. | |
+ */ | |
+ | |
+#include <sys/cdefs.h> | |
+__FBSDID("$FreeBSD: src/sys/amd64/isa/dynticks.c,v 0.1.0 2010/05/02 16:26:20 OZAWATsusyohi Exp $"); | |
+ | |
+#include <sys/dynticks.h> | |
+#include <sys/systm.h> | |
+ | |
+static int enable_dynticks = 0; | |
+static void (*cur_handler)(struct trapframe *frame); | |
+ | |
+static struct timer_ops *tops; | |
+ | |
+void timer_intr_handler(struct trapframe *frame) | |
+{ | |
+ cur_handler(frame); | |
+} | |
+ | |
+void register_timer_intr_handlers(struct timer_ops *ops) | |
+{ | |
+ tops = ops; | |
+ cur_handler = ops->perticks_handler; | |
+ | |
+ if ( tops->perticks_handler && tops->dynticks_handler) { | |
+ enable_dynticks = 1; | |
+ } | |
+} | |
+ | |
+void switch_to_dynticks(void) | |
+{ | |
+ if(!enable_dynticks) | |
+ return; | |
+ | |
+ critical_enter(); | |
+ cur_handler = tops->dynticks_handler; | |
+ tops->set_next_timer_intr(); | |
+ critical_exit(); | |
+} | |
+ | |
+void switch_to_perticks(void) | |
+{ | |
+ if(!enable_dynticks) | |
+ return; | |
+ | |
+ if(!tops->perticks_handler){ | |
+ panic("NULL perticks handler!\n"); | |
+ return; | |
+ } | |
+ | |
+ critical_enter(); | |
+ cur_handler = tops->perticks_handler; | |
+ tops->set_timer_periodic(); | |
+ critical_exit(); | |
+} | |
diff --git a/sys/conf/files.amd64 b/sys/conf/files.amd64 | |
index 44732e8..d20dc77 100644 | |
--- a/sys/conf/files.amd64 | |
+++ b/sys/conf/files.amd64 | |
@@ -123,6 +123,7 @@ amd64/amd64/vm_machdep.c standard | |
amd64/isa/atpic.c optional atpic isa | |
#amd64/isa/atpic_vector.S optional atpic isa | |
amd64/isa/clock.c standard | |
+amd64/isa/dynticks.c standard | |
amd64/isa/elcr.c standard | |
amd64/isa/isa.c standard | |
amd64/isa/isa_dma.c standard | |
diff --git a/sys/conf/files.i386 b/sys/conf/files.i386 | |
index 033999c..ad3c916 100644 | |
--- a/sys/conf/files.i386 | |
+++ b/sys/conf/files.i386 | |
@@ -330,6 +330,7 @@ i386/ibcs2/imgact_coff.c optional ibcs2 | |
i386/isa/atpic.c standard | |
#i386/isa/atpic_vector.s standard | |
i386/isa/clock.c standard | |
+i386/isa/dynticks.c standard | |
i386/isa/dpms.c optional dpms | |
i386/isa/elcr.c standard | |
i386/isa/elink.c optional ep | ie | |
diff --git a/sys/i386/i386/apic_vector.s b/sys/i386/i386/apic_vector.s | |
index c2f5aca..722678c 100644 | |
--- a/sys/i386/i386/apic_vector.s | |
+++ b/sys/i386/i386/apic_vector.s | |
@@ -105,7 +105,7 @@ IDTVEC(timerint) | |
SET_KERNEL_SREGS | |
FAKE_MCOUNT(TF_EIP(%esp)) | |
pushl %esp | |
- call lapic_handle_timer | |
+ call timer_intr_handler | |
add $4, %esp | |
MEXITCOUNT | |
jmp doreti | |
diff --git a/sys/i386/i386/local_apic.c b/sys/i386/i386/local_apic.c | |
index 0151030..19f3853 100644 | |
--- a/sys/i386/i386/local_apic.c | |
+++ b/sys/i386/i386/local_apic.c | |
@@ -66,6 +66,8 @@ __FBSDID("$FreeBSD: src/sys/i386/i386/local_apic.c,v 1.44.2.6.2.1 2010/02/10 00: | |
#include <ddb/ddb.h> | |
#endif | |
+#include <sys/dynticks.h> | |
+ | |
#ifdef KDTRACE_HOOKS | |
#include <sys/dtrace_bsd.h> | |
cyclic_clock_func_t lapic_cyclic_clock_func[MAXCPU]; | |
@@ -109,6 +111,9 @@ struct lapic { | |
u_long la_hard_ticks; | |
u_long la_stat_ticks; | |
u_long la_prof_ticks; | |
+ u_long la_last_tick; | |
+ u_long la_cur_skip; | |
+ u_long la_skip; | |
} static lapics[MAX_APIC_ID + 1]; | |
/* XXX: should thermal be an NMI? */ | |
@@ -142,6 +147,7 @@ static u_int32_t lapic_timer_divisors[] = { | |
APIC_TDCR_32, APIC_TDCR_64, APIC_TDCR_128 | |
}; | |
+ | |
extern inthand_t IDTVEC(rsvd); | |
volatile lapic_t *lapic; | |
@@ -156,6 +162,9 @@ static void lapic_timer_periodic(u_int count); | |
static void lapic_timer_set_divisor(u_int divisor); | |
static uint32_t lvt_mode(struct lapic *la, u_int pin, uint32_t value); | |
+static struct timer_ops lapic_ops; | |
+static void lapic_handle_timer_dynamically(struct trapframe *frame); | |
+ | |
struct pic lapic_pic = { .pic_resume = lapic_resume }; | |
static uint32_t | |
@@ -490,6 +499,8 @@ lapic_setup_clock(void) | |
profhz = lapic_timer_hz; | |
lapic_timer_period = value / lapic_timer_hz; | |
+ register_timer_intr_handlers(&lapic_ops); | |
+ | |
/* | |
* Start up the timer on the BSP. The APs will kick off their | |
* timer during lapic_setup(). | |
@@ -801,6 +812,10 @@ lapic_handle_timer(struct trapframe *frame) | |
if (profprocs != 0) | |
profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); | |
} | |
+ | |
+ la->la_cur_skip = 0; | |
+ la->la_skip = 1; | |
+ | |
critical_exit(); | |
} | |
@@ -1332,3 +1347,108 @@ lapic_ipi_vectored(u_int vector, int dest) | |
#endif /* DETECT_DEADLOCK */ | |
} | |
#endif /* SMP */ | |
+ | |
+static void lapic_set_next_timer_intr(void) | |
+{ | |
+ struct lapic *la; | |
+ int skip; | |
+ u_long cnt_to_skip; | |
+ | |
+ la = &lapics[PCPU_GET(apic_id)]; | |
+ (*la->la_timer_count)++; | |
+ | |
+ skip = callout_get_next_event(); | |
+ cnt_to_skip = lapic_timer_period * skip ; | |
+ lapic_timer_oneshot(cnt_to_skip); | |
+ la->la_skip = skip; | |
+ la->la_cur_skip = 0; | |
+ | |
+ return; | |
+} | |
+ | |
+static void lapic_set_timer_periodic(void) | |
+{ | |
+ lapic_timer_periodic(lapic_timer_period); | |
+} | |
+ | |
+static void | |
+lapic_handle_timer_dynamically(struct trapframe *frame) | |
+{ | |
+ struct lapic *la; | |
+ int skip; | |
+ int i; | |
+ | |
+ /* Send EOI first thing. */ | |
+ lapic_eoi(); | |
+ | |
+#if defined(SMP) && !defined(SCHED_ULE) | |
+ /* | |
+ * Don't do any accounting for the disabled HTT cores, since it | |
+ * will provide misleading numbers for the userland. | |
+ * | |
+ * No locking is necessary here, since even if we loose the race | |
+ * when hlt_cpus_mask changes it is not a big deal, really. | |
+ * | |
+ * Don't do that for ULE, since ULE doesn't consider hlt_cpus_mask | |
+ * and unlike other schedulers it actually schedules threads to | |
+ * those CPUs. | |
+ */ | |
+ if ((hlt_cpus_mask & (1 << PCPU_GET(cpuid))) != 0) | |
+ return; | |
+#endif | |
+ | |
+ /* Look up our local APIC structure for the tick counters. */ | |
+ la = &lapics[PCPU_GET(apic_id)]; | |
+ (*la->la_timer_count)++; | |
+ critical_enter(); | |
+ | |
+#ifdef KDTRACE_HOOKS | |
+ /* | |
+ * If the DTrace hooks are configured and a callback function | |
+ * has been registered, then call it to process the high speed | |
+ * timers. | |
+ */ | |
+ int cpu = PCPU_GET(cpuid); | |
+ /* i dont know this works well? */ | |
+ if (lapic_cyclic_clock_func[cpu] != NULL) | |
+ (*lapic_cyclic_clock_func[cpu])(frame); | |
+#endif | |
+ /* Fire hardclock at hz. */ | |
+ skip = la->la_skip; | |
+ for(i = 0; i < skip; i++){ | |
+ la->la_hard_ticks += hz; | |
+ if (la->la_hard_ticks >= lapic_timer_hz) { | |
+ la->la_hard_ticks -= lapic_timer_hz; | |
+ if (PCPU_GET(cpuid) == 0) | |
+ hardclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); | |
+ else | |
+ hardclock_cpu(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) { | |
+ if (profprocs != 0){ | |
+ la->la_prof_ticks -= lapic_timer_hz; | |
+ profclock(TRAPF_USERMODE(frame), TRAPF_PC(frame)); | |
+ } | |
+ } | |
+ } | |
+ | |
+ lapic_set_next_timer_intr(); | |
+ critical_exit(); | |
+} | |
+ | |
+static struct timer_ops lapic_ops = { | |
+ .perticks_handler = lapic_handle_timer, | |
+ .dynticks_handler = lapic_handle_timer_dynamically, | |
+ .set_timer_periodic = lapic_set_timer_periodic, | |
+ .set_next_timer_intr = lapic_set_next_timer_intr, | |
+}; | |
diff --git a/sys/i386/isa/clock.c b/sys/i386/isa/clock.c | |
index 0b6b42b..3d53dd5 100644 | |
--- a/sys/i386/isa/clock.c | |
+++ b/sys/i386/isa/clock.c | |
@@ -72,6 +72,7 @@ __FBSDID("$FreeBSD: src/sys/i386/isa/clock.c,v 1.239.2.2.6.1 2010/02/10 00:26:20 | |
#include <sys/sysctl.h> | |
#include <sys/cons.h> | |
#include <sys/power.h> | |
+#include <sys/dynticks.h> | |
#include <machine/clock.h> | |
#include <machine/cpu.h> | |
@@ -136,6 +137,8 @@ static unsigned i8254_get_timecount(struct timecounter *tc); | |
static unsigned i8254_simple_get_timecount(struct timecounter *tc); | |
static void set_timer_freq(u_int freq, int intr_freq); | |
+static struct timer_ops clk_ops; | |
+ | |
static struct timecounter i8254_timecounter = { | |
i8254_get_timecount, /* get_timecount */ | |
0, /* no poll_pps */ | |
@@ -769,8 +772,9 @@ cpu_initclocks() | |
* timecounter to user a simpler algorithm. | |
*/ | |
if (!using_lapic_timer) { | |
- intr_add_handler("clk", 0, (driver_filter_t *)clkintr, NULL, | |
- NULL, INTR_TYPE_CLK, NULL); | |
+ register_ext_timer_intr_handlers(&clk_ops); | |
+ intr_add_handler("clk", 0, (driver_filter_t *)ext_timer_intr_handler, NULL, | |
+ NULL, INTR_TYPE_CLK, NULL); | |
i8254_intsrc = intr_lookup_source(0); | |
if (i8254_intsrc != NULL) | |
i8254_pending = | |
@@ -939,4 +943,14 @@ static devclass_t attimer_devclass; | |
DRIVER_MODULE(attimer, isa, attimer_driver, attimer_devclass, 0, 0); | |
DRIVER_MODULE(attimer, acpi, attimer_driver, attimer_devclass, 0, 0); | |
+#if 1 | |
+static struct timer_ops clk_ops = { | |
+ .ext_perticks_handler = clkintr, | |
+ .ext_dynticks_handler = NULL, | |
+ .set_next_timer_intr = NULL, | |
+ .set_timer_periodic = NULL, | |
+}; | |
+#endif | |
+ | |
+ | |
#endif /* DEV_ISA */ | |
diff --git a/sys/i386/isa/dynticks.c b/sys/i386/isa/dynticks.c | |
new file mode 100644 | |
index 0000000..bf5033f | |
--- /dev/null | |
+++ b/sys/i386/isa/dynticks.c | |
@@ -0,0 +1,120 @@ | |
+/*- | |
+ * Copyright (c) 2003 OZAWA Tsuyoshi <[email protected]> | |
+ * All rights reserved. | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * 3. Neither the name of the author nor the names of any co-contributors | |
+ * may be used to endorse or promote products derived from this software | |
+ * without specific prior written permission. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
+ * SUCH DAMAGE. | |
+ */ | |
+ | |
+#include <sys/cdefs.h> | |
+__FBSDID("$FreeBSD: src/sys/amd64/isa/dynticks.c,v 0.1.0 2010/05/02 16:26:20 OZAWATsusyohi Exp $"); | |
+ | |
+#include <sys/dynticks.h> | |
+#include <sys/systm.h> | |
+ | |
+static int enable_dynticks = 0; | |
+static int use_ext_clksrc = 0; | |
+static void (*cur_handler)(struct trapframe *frame); | |
+static int (*cur_ext_handler)(struct trapframe *frame); | |
+ | |
+static struct timer_ops *tops; | |
+ | |
+void timer_intr_handler(struct trapframe *frame) | |
+{ | |
+ if(!cur_handler) | |
+ panic("cur_handler is NULL!\n"); | |
+ | |
+ cur_handler(frame); | |
+} | |
+ | |
+int ext_timer_intr_handler(struct trapframe *frame) | |
+{ | |
+ if(!cur_ext_handler) | |
+ panic("cur_ext_handler is NULL!\n"); | |
+ | |
+ return cur_ext_handler(frame); | |
+} | |
+ | |
+void register_timer_intr_handlers(struct timer_ops *ops) | |
+{ | |
+ tops = ops; | |
+ | |
+ if (ops->perticks_handler) { | |
+ cur_handler = ops->perticks_handler; | |
+ use_ext_clksrc = 0; | |
+ } | |
+ | |
+ if ( tops->perticks_handler && tops->dynticks_handler) { | |
+ enable_dynticks = 1; | |
+ } | |
+} | |
+ | |
+void register_ext_timer_intr_handlers(struct timer_ops *ops) | |
+{ | |
+ tops = ops; | |
+ | |
+ if (tops->ext_perticks_handler) { | |
+ cur_ext_handler = ops->ext_perticks_handler; | |
+ use_ext_clksrc = 1; | |
+ } | |
+ | |
+ if (tops->ext_perticks_handler && tops->ext_dynticks_handler) { | |
+ enable_dynticks = 1; | |
+ } | |
+} | |
+ | |
+void switch_to_dynticks(void) | |
+{ | |
+ if(!enable_dynticks) | |
+ return; | |
+ | |
+ /* TODO: swtich external clock handler */ | |
+ if(use_ext_clksrc) | |
+ return; | |
+ | |
+ critical_enter(); | |
+ cur_handler = tops->dynticks_handler; | |
+ tops->set_next_timer_intr(); | |
+ critical_exit(); | |
+} | |
+ | |
+void switch_to_perticks(void) | |
+{ | |
+ if(!enable_dynticks) | |
+ return; | |
+ | |
+ /* TODO: swtich external clock handler */ | |
+ if(use_ext_clksrc) | |
+ return; | |
+ | |
+ if(!tops->perticks_handler){ | |
+ panic("NULL perticks handler!\n"); | |
+ return; | |
+ } | |
+ | |
+ critical_enter(); | |
+ cur_handler = tops->perticks_handler; | |
+ tops->set_timer_periodic(); | |
+ critical_exit(); | |
+} | |
diff --git a/sys/kern/kern_clock.c b/sys/kern/kern_clock.c | |
index d2faa52..82ab8eb 100644 | |
--- a/sys/kern/kern_clock.c | |
+++ b/sys/kern/kern_clock.c | |
@@ -344,6 +344,33 @@ hardclock(int usermode, uintfptr_t pc) | |
#endif /* SW_WATCHDOG */ | |
} | |
+void | |
+hardclock_dynticks(int usermode, uintfptr_t pc,int skip) | |
+{ | |
+ //int i; | |
+ | |
+ //atomic_add_int((volatile int *)&ticks, skip); // FIXME | |
+ atomic_add_int((volatile int *)&ticks, 1); | |
+ hardclock_cpu(usermode); | |
+ tc_ticktock(); | |
+ /* | |
+ * If no separate statistics clock is available, run it from here. | |
+ * | |
+ * XXX: this only works for UP | |
+ */ | |
+ if (stathz == 0) { | |
+ profclock(usermode, pc); | |
+ statclock(usermode); | |
+ } | |
+#ifdef DEVICE_POLLING | |
+ hardclock_device_poll(); /* this is very short and quick */ | |
+#endif /* DEVICE_POLLING */ | |
+#ifdef SW_WATCHDOG | |
+ if (watchdog_enabled > 0 && (watchdog_ticks -= skip ) <= 0) | |
+ watchdog_fire(); | |
+#endif /* SW_WATCHDOG */ | |
+} | |
+ | |
/* | |
* Compute number of ticks in the specified amount of time. | |
*/ | |
diff --git a/sys/kern/kern_timeout.c b/sys/kern/kern_timeout.c | |
index 658dcc3..f982a77 100644 | |
--- a/sys/kern/kern_timeout.c | |
+++ b/sys/kern/kern_timeout.c | |
@@ -48,6 +48,7 @@ __FBSDID("$FreeBSD: src/sys/kern/kern_timeout.c,v 1.106.2.1.4.1 2010/02/10 00:26 | |
#include <sys/proc.h> | |
#include <sys/sleepqueue.h> | |
#include <sys/sysctl.h> | |
+#include <sys/dynticks.h> | |
static int avg_depth; | |
SYSCTL_INT(_debug, OID_AUTO, to_avg_depth, CTLFLAG_RD, &avg_depth, 0, | |
@@ -704,3 +705,30 @@ adjust_timeout_calltodo(time_change) | |
return; | |
} | |
#endif /* APM_FIXUP_CALLTODO */ | |
+ | |
+int | |
+callout_get_next_event(void) | |
+{ | |
+ struct callout *c; | |
+ struct callout_tailq *sc; | |
+ int curticks; | |
+ int skip = 1; | |
+ | |
+ curticks = softticks; | |
+ | |
+ while( skip < ncallout ) { | |
+ sc = &callwheel[ (curticks+skip) & callwheelmask ]; | |
+ /* scan callout queue to get next timer event */ | |
+ TAILQ_FOREACH( c, sc, c_links.tqe ){ | |
+ if( c && c->c_time <= curticks + ncallout ){ | |
+ if( c->c_time > 0 ){ | |
+ goto out; | |
+ } | |
+ } | |
+ } | |
+ skip++; | |
+ } | |
+ | |
+out: | |
+ return skip; | |
+} | |
diff --git a/sys/kern/sched_4bsd.c b/sys/kern/sched_4bsd.c | |
index b9871b8..e12d45b 100644 | |
--- a/sys/kern/sched_4bsd.c | |
+++ b/sys/kern/sched_4bsd.c | |
@@ -54,6 +54,7 @@ __FBSDID("$FreeBSD: src/sys/kern/sched_4bsd.c,v 1.106.2.9.2.1 2010/02/10 00:26:2 | |
#include <sys/sx.h> | |
#include <sys/turnstile.h> | |
#include <sys/umtx.h> | |
+#include <sys/dynticks.h> | |
#include <machine/pcb.h> | |
#include <machine/smp.h> | |
@@ -1430,8 +1431,10 @@ sched_idletd(void *dummy) | |
for (;;) { | |
mtx_assert(&Giant, MA_NOTOWNED); | |
+ switch_to_dynticks(); | |
while (sched_runnable() == 0) | |
cpu_idle(); | |
+ switch_to_perticks(); | |
mtx_lock_spin(&sched_lock); | |
mi_switch(SW_VOL, NULL); | |
diff --git a/sys/kern/sched_ule.c b/sys/kern/sched_ule.c | |
index 7943bb2..1bf9e31 100644 | |
--- a/sys/kern/sched_ule.c | |
+++ b/sys/kern/sched_ule.c | |
@@ -61,6 +61,7 @@ __FBSDID("$FreeBSD: src/sys/kern/sched_ule.c,v 1.214.2.12.2.1 2010/02/10 00:26:2 | |
#include <sys/umtx.h> | |
#include <sys/vmmeter.h> | |
#include <sys/cpuset.h> | |
+#include <sys/dynticks.h> | |
#ifdef KTRACE | |
#include <sys/uio.h> | |
#include <sys/ktrace.h> | |
@@ -2670,12 +2671,14 @@ sched_idletd(void *dummy) | |
mtx_assert(&Giant, MA_NOTOWNED); | |
/* ULE relies on preemption for idle interruption. */ | |
for (;;) { | |
+ switch_to_dynticks(); | |
#ifdef SMP | |
if (tdq_idled(tdq)) | |
cpu_idle(); | |
#else | |
cpu_idle(); | |
#endif | |
+ switch_to_perticks(); | |
} | |
} | |
diff --git a/sys/sys/dynticks.h b/sys/sys/dynticks.h | |
new file mode 100644 | |
index 0000000..5b268cd | |
--- /dev/null | |
+++ b/sys/sys/dynticks.h | |
@@ -0,0 +1,49 @@ | |
+#ifndef _SYS_DYNTICKS_H_ | |
+#define _SYS_DYNTICKS_H_ | |
+ | |
+/*- | |
+ * Copyright (c) 2010 Tsuyoshi OZAWA | |
+ * All rights reserved. | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND | |
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE | |
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
+ * SUCH DAMAGE. | |
+ * | |
+ */ | |
+#include <sys/types.h> | |
+#include <machine/frame.h> | |
+ | |
+struct timer_ops { | |
+ void (*perticks_handler)(struct trapframe *frame); | |
+ int (*ext_perticks_handler)(struct trapframe *frame); | |
+ void (*dynticks_handler)(struct trapframe *frame); | |
+ int (*ext_dynticks_handler)(struct trapframe *frame); | |
+ void (*set_timer_periodic)(void); | |
+ void (*set_next_timer_intr)(void); | |
+}; | |
+ | |
+void timer_intr_handler(struct trapframe *frame); | |
+int ext_timer_intr_handler(struct trapframe *frame); | |
+int callout_get_next_event(void); | |
+void register_timer_intr_handlers(struct timer_ops *ops); | |
+void register_ext_timer_intr_handlers(struct timer_ops *ops); | |
+void switch_to_dynticks(void); | |
+void switch_to_perticks(void); | |
+#endif /* _SYS_DYNTICKS_H_ */ | |
diff --git a/sys/sys/systm.h b/sys/sys/systm.h | |
index 45969b3..9d6525d 100644 | |
--- a/sys/sys/systm.h | |
+++ b/sys/sys/systm.h | |
@@ -232,6 +232,7 @@ u_long casuword(volatile u_long *p, u_long oldval, u_long newval); | |
void realitexpire(void *); | |
void hardclock(int usermode, uintfptr_t pc); | |
+void hardclock_dynticks(int usermode, uintfptr_t pc,int skip); | |
void hardclock_cpu(int usermode); | |
void softclock(void *); | |
void statclock(int usermode); | |
-- | |
1.7.0.1 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment