From: Rusty Russell <rusty@rustcorp.com.au>
To: Andrew Morton <akpm@linux-foundation.org>
Cc: lkml - Kernel Mailing List <linux-kernel@vger.kernel.org>,
James Morris <jmorris@namei.org>, Ingo Molnar <mingo@elte.hu>,
Thomas Gleixner <tglx@linutronix.de>
Subject: [PATCH 6/6] lguest use hrtimers
Date: Wed, 06 Jun 2007 01:09:56 +1000 [thread overview]
Message-ID: <1181056196.14054.53.camel@localhost.localdomain> (raw)
In-Reply-To: <1181055760.14054.47.camel@localhost.localdomain>
(BTW Thomas, is the check for delta < minimum actually required in our
set_next_event function?)
>From jmorris@namei.org Wed May 9 23:37:36 2007
Convert lguest to the hrtimer framework, enabling dynamic ticks and high
resolution timers.
Signed-off-by: James Morris <jmorris@namei.org>
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
---
drivers/lguest/core.c | 2 -
drivers/lguest/hypercalls.c | 10 +----
drivers/lguest/interrupts_and_traps.c | 34 +++++++++++++++--
drivers/lguest/lg.h | 6 ++-
drivers/lguest/lguest.c | 63 +++++++++++++++++++++++++++++++--
drivers/lguest/lguest_user.c | 3 +
include/linux/lguest.h | 5 ++
7 files changed, 106 insertions(+), 17 deletions(-)
===================================================================
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -329,7 +329,7 @@ int run_guest(struct lguest *lg, unsigne
if (lg->halted) {
set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(1);
+ schedule();
continue;
}
===================================================================
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -44,13 +44,6 @@ static void do_hcall(struct lguest *lg,
else
guest_pagetable_flush_user(lg);
break;
- case LHCALL_TIMER_READ: {
- u32 now = jiffies;
- mb();
- regs->eax = now - lg->last_timer;
- lg->last_timer = now;
- break;
- }
case LHCALL_GET_WALLCLOCK: {
struct timespec ts;
ktime_get_real_ts(&ts);
@@ -84,6 +77,9 @@ static void do_hcall(struct lguest *lg,
break;
case LHCALL_LOAD_TLS:
guest_load_tls(lg, regs->edx);
+ break;
+ case LHCALL_SET_CLOCKEVENT:
+ guest_set_clockevent(lg, regs->edx);
break;
case LHCALL_TS:
lg->ts = regs->edx;
===================================================================
--- a/drivers/lguest/interrupts_and_traps.c
+++ b/drivers/lguest/interrupts_and_traps.c
@@ -72,10 +72,6 @@ void maybe_do_interrupt(struct lguest *l
if (!lg->lguest_data)
return;
-
- /* If timer has changed, set timer interrupt. */
- if (jiffies != lg->last_timer)
- set_bit(0, lg->irqs_pending);
/* Mask out any interrupts they have blocked. */
if (copy_from_user(&blk, lg->lguest_data->blocked_interrupts,
@@ -240,3 +236,33 @@ void copy_traps(const struct lguest *lg,
else
default_idt_entry(&idt[i], i, def[i]);
}
+
+void guest_set_clockevent(struct lguest *lg, unsigned long delta)
+{
+ ktime_t expires;
+
+ if (unlikely(delta == 0)) {
+ /* Clock event device is shutting down. */
+ hrtimer_cancel(&lg->hrt);
+ return;
+ }
+
+ expires = ktime_add_ns(ktime_get_real(), delta);
+ hrtimer_start(&lg->hrt, expires, HRTIMER_MODE_ABS);
+}
+
+static enum hrtimer_restart clockdev_fn(struct hrtimer *timer)
+{
+ struct lguest *lg = container_of(timer, struct lguest, hrt);
+
+ set_bit(0, lg->irqs_pending);
+ if (lg->halted)
+ wake_up_process(lg->tsk);
+ return HRTIMER_NORESTART;
+}
+
+void init_clockdev(struct lguest *lg)
+{
+ hrtimer_init(&lg->hrt, CLOCK_REALTIME, HRTIMER_MODE_ABS);
+ lg->hrt.function = clockdev_fn;
+}
===================================================================
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -134,7 +134,6 @@ struct lguest
u32 cr2;
int halted;
int ts;
- u32 last_timer;
u32 next_hcall;
u32 esp1;
u8 ss1;
@@ -173,6 +172,9 @@ struct lguest
/* The IDT entries: some copied into lguest_ro_state when running. */
struct desc_struct idt[FIRST_EXTERNAL_VECTOR+LGUEST_IRQS];
struct desc_struct syscall_idt;
+
+ /* Virtual clock device */
+ struct hrtimer hrt;
/* Pending virtual interrupts */
DECLARE_BITMAP(irqs_pending, LGUEST_IRQS);
@@ -202,6 +204,8 @@ void setup_default_idt_entries(struct lg
const unsigned long *def);
void copy_traps(const struct lguest *lg, struct desc_struct *idt,
const unsigned long *def);
+void guest_set_clockevent(struct lguest *lg, unsigned long delta);
+void init_clockdev(struct lguest *lg);
/* segments.c: */
void setup_default_gdt_entries(struct lguest_ro_state *state);
===================================================================
--- a/drivers/lguest/lguest.c
+++ b/drivers/lguest/lguest.c
@@ -26,6 +26,7 @@
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <linux/clocksource.h>
+#include <linux/clockchips.h>
#include <linux/lguest.h>
#include <linux/lguest_launcher.h>
#include <linux/lguest_bus.h>
@@ -359,8 +360,58 @@ static struct clocksource lguest_clock =
.flags = CLOCK_SOURCE_IS_CONTINUOUS,
};
+/* We also need a "struct clock_event_device": Linux asks us to set it to go
+ * off some time in the future. Actually, James Morris figured all this out, I
+ * just applied the patch. */
+static int lguest_clockevent_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ if (delta < LG_CLOCK_MIN_DELTA) {
+ if (printk_ratelimit())
+ printk(KERN_DEBUG "%s: small delta %lu ns\n",
+ __FUNCTION__, delta);
+ return -ETIME;
+ }
+ hcall(LHCALL_SET_CLOCKEVENT, delta, 0, 0);
+ return 0;
+}
+
+static void lguest_clockevent_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ /* A 0 argument shuts the clock down. */
+ hcall(LHCALL_SET_CLOCKEVENT, 0, 0, 0);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* This is what we expect. */
+ break;
+ case CLOCK_EVT_MODE_PERIODIC:
+ BUG();
+ }
+}
+
+/* This describes our primitive timer chip. */
+static struct clock_event_device lguest_clockevent = {
+ .name = "lguest",
+ .features = CLOCK_EVT_FEAT_ONESHOT,
+ .set_next_event = lguest_clockevent_set_next_event,
+ .set_mode = lguest_clockevent_set_mode,
+ .rating = INT_MAX,
+ .mult = 1,
+ .shift = 0,
+ .min_delta_ns = LG_CLOCK_MIN_DELTA,
+ .max_delta_ns = LG_CLOCK_MAX_DELTA,
+};
+
+/* This is the Guest timer interrupt handler (hardware interrupt 0). We just
+ * call the clockevent infrastructure and it does whatever needs doing. */
static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
{
+ unsigned long flags;
+
/* Check in case host TSC has changed rate. */
if (unlikely(tsc_khz != lguest_data.tsc_khz)) {
tsc_khz = lguest_data.tsc_khz;
@@ -368,8 +419,11 @@ static void lguest_time_irq(unsigned int
__get_cpu_var(sc_data).cyc2ns_scale
= (1000000 << CYC2NS_SCALE_FACTOR) / tsc_khz;
}
- do_timer(hcall(LHCALL_TIMER_READ, 0, 0, 0));
- update_process_times(user_mode_vm(get_irq_regs()));
+
+ /* Don't interrupt us while this is running. */
+ local_irq_save(flags);
+ lguest_clockevent.event_handler(&lguest_clockevent);
+ local_irq_restore(flags);
}
static void lguest_time_init(void)
@@ -379,7 +433,10 @@ static void lguest_time_init(void)
lguest_clock.mult = clocksource_khz2mult(tsc_khz, 22);
clocksource_register(&lguest_clock);
- hcall(LHCALL_TIMER_READ, 0, 0, 0);
+ /* We can't set cpumask in the initializer: damn C limitations! */
+ lguest_clockevent.cpumask = cpumask_of_cpu(0);
+ clockevents_register_device(&lguest_clockevent);
+
enable_lguest_irq(0);
}
===================================================================
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -139,6 +139,7 @@ static int initialize(struct file *file,
setup_regs(lg->regs, args[2]);
setup_guest_gdt(lg);
+ init_clockdev(lg);
lg->tsk = current;
get_task_struct(lg->tsk);
lg->mm = get_task_mm(lg->tsk);
@@ -200,6 +201,8 @@ static int close(struct inode *inode, st
return 0;
mutex_lock(&lguest_lock);
+ /* Cancels the hrtimer set via LHCALL_SET_CLOCKEVENT. */
+ hrtimer_cancel(&lg->hrt);
release_all_dma(lg);
free_guest_pagetable(lg);
put_task_struct(lg->tsk);
===================================================================
--- a/include/linux/lguest.h
+++ b/include/linux/lguest.h
@@ -15,7 +15,7 @@
#define LHCALL_LOAD_IDT_ENTRY 6
#define LHCALL_SET_STACK 7
#define LHCALL_TS 8
-#define LHCALL_TIMER_READ 9
+#define LHCALL_SET_CLOCKEVENT 9
#define LHCALL_HALT 10
#define LHCALL_GET_WALLCLOCK 11
#define LHCALL_BIND_DMA 12
@@ -23,6 +23,9 @@
#define LHCALL_SET_PTE 14
#define LHCALL_SET_PMD 15
#define LHCALL_LOAD_TLS 16
+
+#define LG_CLOCK_MIN_DELTA 100UL
+#define LG_CLOCK_MAX_DELTA ULONG_MAX
#define LGUEST_TRAP_ENTRY 0x1F
next prev parent reply other threads:[~2007-06-05 15:29 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-06-05 14:55 [PATCH 1/6] lguest example launcher fix Rusty Russell
2007-06-05 14:56 ` [PATCH 2/6] lguest tsc fix Rusty Russell
2007-06-05 14:58 ` [PATCH 3/6] lguest suppress IDE probing Rusty Russell
2007-06-05 15:00 ` [PATCH 4/6] lguest don't signal like crazy, use LHREQ_BREAK command Rusty Russell
2007-06-05 15:02 ` [PATCH 5/6] lguest use TSC Rusty Russell
2007-06-05 15:09 ` Rusty Russell [this message]
2007-06-05 15:34 ` [PATCH 4/6] lguest don't signal like crazy, use LHREQ_BREAK command Matt Mackall
2007-06-06 0:07 ` Rusty Russell
2007-06-06 1:00 ` Matt Mackall
2007-06-05 15:32 ` [PATCH 3/6] lguest suppress IDE probing Matt Mackall
2007-06-05 16:07 ` Alan Cox
2007-06-05 16:10 ` Jeff Garzik
2007-06-05 17:09 ` James Morris
2007-06-06 1:10 ` Rusty Russell
2007-06-06 10:23 ` Alan Cox
2007-06-07 2:13 ` Rusty Russell
2007-06-07 14:45 ` Matt Mackall
2007-06-05 18:15 ` [PATCH 2/6] lguest tsc fix Andi Kleen
2007-06-06 0:25 ` Rusty Russell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1181056196.14054.53.camel@localhost.localdomain \
--to=rusty@rustcorp.com.au \
--cc=akpm@linux-foundation.org \
--cc=jmorris@namei.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.