aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristian Borntraeger <borntraeger@de.ibm.com>2009-05-12 11:21:49 -0400
committerAvi Kivity <avi@redhat.com>2009-06-10 04:48:55 -0400
commitca8723023f25c9a70d76cbd6101f8fb4ffec2fa0 (patch)
treeef753d244a55271279b5b2cf29b28db5b35b454c
parent2668dab794272f0898491acaf1e77e9a005abc0f (diff)
KVM: s390: use hrtimer for clock wakeup from idle - v2
This patch reworks the s390 clock comparator wakeup to hrtimer. The clock comparator is a per-cpu value that is compared against the TOD clock. If ckc <= TOD an external interrupt 1004 is triggered. Since the clock comparator and the TOD clock have a much higher resolution than jiffies we should use hrtimers to trigger the wakeup. This speeds up guest nanosleep for small values. Since hrtimers callbacks run in hard-irq context, I added a tasklet to do the actual work with enabled interrupts. Signed-off-by: Christian Borntraeger <borntraeger@de.ibm.com> Signed-off-by: Carsten Otte <cotte@de.ibm.com> Signed-off-by: Christian Ehrhardt <ehrhardt@de.ibm.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/s390/include/asm/kvm_host.h5
-rw-r--r--arch/s390/kvm/interrupt.c33
-rw-r--r--arch/s390/kvm/kvm-s390.c7
-rw-r--r--arch/s390/kvm/kvm-s390.h4
4 files changed, 35 insertions, 14 deletions
diff --git a/arch/s390/include/asm/kvm_host.h b/arch/s390/include/asm/kvm_host.h
index 54ea39f96ecd..a27d0d5a6f86 100644
--- a/arch/s390/include/asm/kvm_host.h
+++ b/arch/s390/include/asm/kvm_host.h
@@ -13,6 +13,8 @@
13 13
14#ifndef ASM_KVM_HOST_H 14#ifndef ASM_KVM_HOST_H
15#define ASM_KVM_HOST_H 15#define ASM_KVM_HOST_H
16#include <linux/hrtimer.h>
17#include <linux/interrupt.h>
16#include <linux/kvm_host.h> 18#include <linux/kvm_host.h>
17#include <asm/debug.h> 19#include <asm/debug.h>
18#include <asm/cpuid.h> 20#include <asm/cpuid.h>
@@ -210,7 +212,8 @@ struct kvm_vcpu_arch {
210 s390_fp_regs guest_fpregs; 212 s390_fp_regs guest_fpregs;
211 unsigned int guest_acrs[NUM_ACRS]; 213 unsigned int guest_acrs[NUM_ACRS];
212 struct kvm_s390_local_interrupt local_int; 214 struct kvm_s390_local_interrupt local_int;
213 struct timer_list ckc_timer; 215 struct hrtimer ckc_timer;
216 struct tasklet_struct tasklet;
214 union { 217 union {
215 cpuid_t cpu_id; 218 cpuid_t cpu_id;
216 u64 stidp_data; 219 u64 stidp_data;
diff --git a/arch/s390/kvm/interrupt.c b/arch/s390/kvm/interrupt.c
index 4ed4c3a11485..a48830fa9c59 100644
--- a/arch/s390/kvm/interrupt.c
+++ b/arch/s390/kvm/interrupt.c
@@ -12,6 +12,8 @@
12 12
13#include <asm/lowcore.h> 13#include <asm/lowcore.h>
14#include <asm/uaccess.h> 14#include <asm/uaccess.h>
15#include <linux/hrtimer.h>
16#include <linux/interrupt.h>
15#include <linux/kvm_host.h> 17#include <linux/kvm_host.h>
16#include <linux/signal.h> 18#include <linux/signal.h>
17#include "kvm-s390.h" 19#include "kvm-s390.h"
@@ -361,12 +363,10 @@ int kvm_s390_handle_wait(struct kvm_vcpu *vcpu)
361 return 0; 363 return 0;
362 } 364 }
363 365
364 sltime = (vcpu->arch.sie_block->ckc - now) / (0xf4240000ul / HZ) + 1; 366 sltime = ((vcpu->arch.sie_block->ckc - now)*125)>>9;
365 367
366 vcpu->arch.ckc_timer.expires = jiffies + sltime; 368 hrtimer_start(&vcpu->arch.ckc_timer, ktime_set (0, sltime) , HRTIMER_MODE_REL);
367 369 VCPU_EVENT(vcpu, 5, "enabled wait via clock comparator: %llx ns", sltime);
368 add_timer(&vcpu->arch.ckc_timer);
369 VCPU_EVENT(vcpu, 5, "enabled wait timer:%llx jiffies", sltime);
370no_timer: 370no_timer:
371 spin_lock_bh(&vcpu->arch.local_int.float_int->lock); 371 spin_lock_bh(&vcpu->arch.local_int.float_int->lock);
372 spin_lock_bh(&vcpu->arch.local_int.lock); 372 spin_lock_bh(&vcpu->arch.local_int.lock);
@@ -389,21 +389,34 @@ no_timer:
389 remove_wait_queue(&vcpu->wq, &wait); 389 remove_wait_queue(&vcpu->wq, &wait);
390 spin_unlock_bh(&vcpu->arch.local_int.lock); 390 spin_unlock_bh(&vcpu->arch.local_int.lock);
391 spin_unlock_bh(&vcpu->arch.local_int.float_int->lock); 391 spin_unlock_bh(&vcpu->arch.local_int.float_int->lock);
392 del_timer(&vcpu->arch.ckc_timer); 392 hrtimer_try_to_cancel(&vcpu->arch.ckc_timer);
393 return 0; 393 return 0;
394} 394}
395 395
396void kvm_s390_idle_wakeup(unsigned long data) 396void kvm_s390_tasklet(unsigned long parm)
397{ 397{
398 struct kvm_vcpu *vcpu = (struct kvm_vcpu *)data; 398 struct kvm_vcpu *vcpu = (struct kvm_vcpu *) parm;
399 399
400 spin_lock_bh(&vcpu->arch.local_int.lock); 400 spin_lock(&vcpu->arch.local_int.lock);
401 vcpu->arch.local_int.timer_due = 1; 401 vcpu->arch.local_int.timer_due = 1;
402 if (waitqueue_active(&vcpu->arch.local_int.wq)) 402 if (waitqueue_active(&vcpu->arch.local_int.wq))
403 wake_up_interruptible(&vcpu->arch.local_int.wq); 403 wake_up_interruptible(&vcpu->arch.local_int.wq);
404 spin_unlock_bh(&vcpu->arch.local_int.lock); 404 spin_unlock(&vcpu->arch.local_int.lock);
405} 405}
406 406
407/*
408 * low level hrtimer wake routine. Because this runs in hardirq context
409 * we schedule a tasklet to do the real work.
410 */
411enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer)
412{
413 struct kvm_vcpu *vcpu;
414
415 vcpu = container_of(timer, struct kvm_vcpu, arch.ckc_timer);
416 tasklet_schedule(&vcpu->arch.tasklet);
417
418 return HRTIMER_NORESTART;
419}
407 420
408void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu) 421void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu)
409{ 422{
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 86567e174fd7..dc3d06811fd8 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -15,6 +15,7 @@
15#include <linux/compiler.h> 15#include <linux/compiler.h>
16#include <linux/err.h> 16#include <linux/err.h>
17#include <linux/fs.h> 17#include <linux/fs.h>
18#include <linux/hrtimer.h>
18#include <linux/init.h> 19#include <linux/init.h>
19#include <linux/kvm.h> 20#include <linux/kvm.h>
20#include <linux/kvm_host.h> 21#include <linux/kvm_host.h>
@@ -283,8 +284,10 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
283 vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin; 284 vcpu->arch.sie_block->gmsor = vcpu->kvm->arch.guest_origin;
284 vcpu->arch.sie_block->ecb = 2; 285 vcpu->arch.sie_block->ecb = 2;
285 vcpu->arch.sie_block->eca = 0xC1002001U; 286 vcpu->arch.sie_block->eca = 0xC1002001U;
286 setup_timer(&vcpu->arch.ckc_timer, kvm_s390_idle_wakeup, 287 hrtimer_init(&vcpu->arch.ckc_timer, CLOCK_REALTIME, HRTIMER_MODE_ABS);
287 (unsigned long) vcpu); 288 tasklet_init(&vcpu->arch.tasklet, kvm_s390_tasklet,
289 (unsigned long) vcpu);
290 vcpu->arch.ckc_timer.function = kvm_s390_idle_wakeup;
288 get_cpu_id(&vcpu->arch.cpu_id); 291 get_cpu_id(&vcpu->arch.cpu_id);
289 vcpu->arch.cpu_id.version = 0xff; 292 vcpu->arch.cpu_id.version = 0xff;
290 return 0; 293 return 0;
diff --git a/arch/s390/kvm/kvm-s390.h b/arch/s390/kvm/kvm-s390.h
index 00bbe69b78da..748fee872323 100644
--- a/arch/s390/kvm/kvm-s390.h
+++ b/arch/s390/kvm/kvm-s390.h
@@ -14,6 +14,7 @@
14#ifndef ARCH_S390_KVM_S390_H 14#ifndef ARCH_S390_KVM_S390_H
15#define ARCH_S390_KVM_S390_H 15#define ARCH_S390_KVM_S390_H
16 16
17#include <linux/hrtimer.h>
17#include <linux/kvm.h> 18#include <linux/kvm.h>
18#include <linux/kvm_host.h> 19#include <linux/kvm_host.h>
19 20
@@ -41,7 +42,8 @@ static inline int __cpu_is_stopped(struct kvm_vcpu *vcpu)
41} 42}
42 43
43int kvm_s390_handle_wait(struct kvm_vcpu *vcpu); 44int kvm_s390_handle_wait(struct kvm_vcpu *vcpu);
44void kvm_s390_idle_wakeup(unsigned long data); 45enum hrtimer_restart kvm_s390_idle_wakeup(struct hrtimer *timer);
46void kvm_s390_tasklet(unsigned long parm);
45void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu); 47void kvm_s390_deliver_pending_interrupts(struct kvm_vcpu *vcpu);
46int kvm_s390_inject_vm(struct kvm *kvm, 48int kvm_s390_inject_vm(struct kvm *kvm,
47 struct kvm_s390_interrupt *s390int); 49 struct kvm_s390_interrupt *s390int);