From acea2953e72aac894b7fd7e0856fc940cb745c1e Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 21 Mar 2007 12:03:27 -0400 Subject: [PATCH] lguest: TSC clocksource Add rudimentary TSC-based clocksource support. Needs to be enhanced for frequency scaling. Signed-off-by: James Morris --- arch/i386/kernel/tsc.c | 1 + arch/i386/lguest/hypercalls.c | 3 +++ arch/i386/lguest/lguest.c | 25 +++++++++++++++++++++++++ include/asm-i386/lguest.h | 2 ++ 4 files changed, 31 insertions(+), 0 deletions(-) diff --git a/arch/i386/kernel/tsc.c b/arch/i386/kernel/tsc.c index 755209d..8abc14c 100644 --- a/arch/i386/kernel/tsc.c +++ b/arch/i386/kernel/tsc.c @@ -26,6 +26,7 @@ static int tsc_enabled; * an extra value to store the TSC freq */ unsigned int tsc_khz; +EXPORT_SYMBOL_GPL(tsc_khz); int tsc_disable; diff --git a/arch/i386/lguest/hypercalls.c b/arch/i386/lguest/hypercalls.c index 03ec5f6..ee3a3f4 100644 --- a/arch/i386/lguest/hypercalls.c +++ b/arch/i386/lguest/hypercalls.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -174,6 +175,8 @@ int hypercall(struct lguest *lg, struct /* We reserve the top pgd entry. */ put_user(4U*1024*1024, &lg->lguest_data->reserve_mem); put_user(lg->guestid, &lg->lguest_data->guestid); + put_user(clocksource_khz2mult(tsc_khz, 22), + &lg->lguest_data->clock_mult); return 0; } pending = do_hcall(lg, regs); diff --git a/arch/i386/lguest/lguest.c b/arch/i386/lguest/lguest.c index 00c3a95..88254d1 100644 --- a/arch/i386/lguest/lguest.c +++ b/arch/i386/lguest/lguest.c @@ -50,6 +50,7 @@ #include #include #include #include +#include #include #include #include @@ -597,6 +598,29 @@ static void lguest_time_irq(unsigned int update_process_times(user_mode_vm(get_irq_regs())); } +static cycle_t lguest_clock_read(void) +{ + /* FIXME: This is just the native one. Account stolen time! */ + return paravirt_ops.read_tsc(); +} + +/* FIXME: Update iff tsc rate changes. */ +static struct clocksource lguest_clock = { + .name = "lguest", + .rating = 400, + .read = lguest_clock_read, + .mask = CLOCKSOURCE_MASK(64), + .mult = 0, /* to be set */ + .shift = 22, + .flags = CLOCK_SOURCE_IS_CONTINUOUS, +}; + +static void lguest_setup_clocksource(void) +{ + lguest_clock.mult = lguest_data.clock_mult; + clocksource_register(&lguest_clock); +} + /* At some point in the boot process, we get asked to set up our timing * infrastructure. The kernel doesn't expect timer interrupts before this, but * we cleverly initialized the "interrupts" field of lguest_data so that timer @@ -611,6 +635,7 @@ static void lguest_time_irq(unsigned int static void lguest_time_init(void) { set_irq_handler(0, lguest_time_irq); + lguest_setup_clocksource(); hcall(LHCALL_TIMER_READ, 0, 0, 0); enable_lguest_irq(0); } diff --git a/include/asm-i386/lguest.h b/include/asm-i386/lguest.h index ae11a4b..2373ade 100644 --- a/include/asm-i386/lguest.h +++ b/include/asm-i386/lguest.h @@ -100,6 +100,8 @@ struct lguest_data unsigned long reserve_mem; /* ID of this guest (used by network driver to set ethernet address) */ u16 guestid; + /* Multiplier for TSC clock. */ + u32 clock_mult; /* Fields initialized by the guest at boot: */ /* Instruction range to suppress interrupts even if enabled */ -- 1.4.2.1