From 8b8a9d0943c34df1dfb6208f9e6e39c8257039f5 Mon Sep 17 00:00:00 2001 From: James Morris Date: Thu, 29 Mar 2007 11:36:01 -0400 Subject: [PATCH] From: Rusty Russell lguest: TSC clocksource Add rudimentary TSC-based clocksource support (Rusty's original patch). Needs to be enhanced for frequency scaling. Signed-off-by: James Morris --- arch/i386/kernel/tsc.c | 1 + drivers/lguest/hypercalls.c | 2 ++ drivers/lguest/lguest.c | 24 ++++++++++++++++++++++++ include/linux/lguest.h | 2 ++ 4 files changed, 29 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/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c index 4c5fd28..ae11fd0 100644 --- a/drivers/lguest/hypercalls.c +++ b/drivers/lguest/hypercalls.c @@ -159,6 +159,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/drivers/lguest/lguest.c b/drivers/lguest/lguest.c index f278e36..62e3149 100644 --- a/drivers/lguest/lguest.c +++ b/drivers/lguest/lguest.c @@ -598,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 @@ -612,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/linux/lguest.h b/include/linux/lguest.h index a8bee7d..71165f2 100644 --- a/include/linux/lguest.h +++ b/include/linux/lguest.h @@ -101,6 +101,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