Skip to content

Instantly share code, notes, and snippets.

@oza
Created May 1, 2010 02:58
Show Gist options
  • Save oza/386004 to your computer and use it in GitHub Desktop.
Save oza/386004 to your computer and use it in GitHub Desktop.
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