aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2008-12-30 12:55:06 -0500
committerAvi Kivity <avi@redhat.com>2009-03-24 05:02:55 -0400
commit52d939a0bf44081bc9f69b4fbdc9e7f416df27c7 (patch)
tree27a14385847f5585cdccaf5e5c18074595642970
parent61a6bd672bda3b9468bf5895c1be085c4e481138 (diff)
KVM: PIT: provide an option to disable interrupt reinjection
Certain clocks (such as TSC) in older 2.6 guests overaccount for lost ticks, causing severe time drift. Interrupt reinjection magnifies the problem. Provide an option to disable it. [avi: allow room for expansion in case we want to disable reinjection of other timers] Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com> Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--arch/x86/include/asm/kvm.h5
-rw-r--r--arch/x86/kvm/i8254.c4
-rw-r--r--arch/x86/kvm/i8254.h1
-rw-r--r--arch/x86/kvm/x86.c21
-rw-r--r--include/linux/kvm.h4
5 files changed, 35 insertions, 0 deletions
diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index 32eb96c7ca27..54bcf2281526 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -233,4 +233,9 @@ struct kvm_guest_debug_arch {
233struct kvm_pit_state { 233struct kvm_pit_state {
234 struct kvm_pit_channel_state channels[3]; 234 struct kvm_pit_channel_state channels[3];
235}; 235};
236
237struct kvm_reinject_control {
238 __u8 pit_reinject;
239 __u8 reserved[31];
240};
236#endif /* _ASM_X86_KVM_H */ 241#endif /* _ASM_X86_KVM_H */
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index 72bd275a9b5c..528daadeba49 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -201,6 +201,9 @@ static int __pit_timer_fn(struct kvm_kpit_state *ps)
201 if (!atomic_inc_and_test(&pt->pending)) 201 if (!atomic_inc_and_test(&pt->pending))
202 set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests); 202 set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests);
203 203
204 if (!pt->reinject)
205 atomic_set(&pt->pending, 1);
206
204 if (vcpu0 && waitqueue_active(&vcpu0->wq)) 207 if (vcpu0 && waitqueue_active(&vcpu0->wq))
205 wake_up_interruptible(&vcpu0->wq); 208 wake_up_interruptible(&vcpu0->wq);
206 209
@@ -580,6 +583,7 @@ struct kvm_pit *kvm_create_pit(struct kvm *kvm)
580 pit_state->irq_ack_notifier.gsi = 0; 583 pit_state->irq_ack_notifier.gsi = 0;
581 pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq; 584 pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq;
582 kvm_register_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier); 585 kvm_register_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier);
586 pit_state->pit_timer.reinject = true;
583 mutex_unlock(&pit->pit_state.lock); 587 mutex_unlock(&pit->pit_state.lock);
584 588
585 kvm_pit_reset(pit); 589 kvm_pit_reset(pit);
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h
index 4178022b97aa..76959c4b500e 100644
--- a/arch/x86/kvm/i8254.h
+++ b/arch/x86/kvm/i8254.h
@@ -9,6 +9,7 @@ struct kvm_kpit_timer {
9 s64 period; /* unit: ns */ 9 s64 period; /* unit: ns */
10 s64 scheduled; 10 s64 scheduled;
11 atomic_t pending; 11 atomic_t pending;
12 bool reinject;
12}; 13};
13 14
14struct kvm_kpit_channel_state { 15struct kvm_kpit_channel_state {
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index c3fbe8c55c13..a1f14611f4b9 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -993,6 +993,7 @@ int kvm_dev_ioctl_check_extension(long ext)
993 case KVM_CAP_NOP_IO_DELAY: 993 case KVM_CAP_NOP_IO_DELAY:
994 case KVM_CAP_MP_STATE: 994 case KVM_CAP_MP_STATE:
995 case KVM_CAP_SYNC_MMU: 995 case KVM_CAP_SYNC_MMU:
996 case KVM_CAP_REINJECT_CONTROL:
996 r = 1; 997 r = 1;
997 break; 998 break;
998 case KVM_CAP_COALESCED_MMIO: 999 case KVM_CAP_COALESCED_MMIO:
@@ -1728,6 +1729,15 @@ static int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
1728 return r; 1729 return r;
1729} 1730}
1730 1731
1732static int kvm_vm_ioctl_reinject(struct kvm *kvm,
1733 struct kvm_reinject_control *control)
1734{
1735 if (!kvm->arch.vpit)
1736 return -ENXIO;
1737 kvm->arch.vpit->pit_state.pit_timer.reinject = control->pit_reinject;
1738 return 0;
1739}
1740
1731/* 1741/*
1732 * Get (and clear) the dirty memory log for a memory slot. 1742 * Get (and clear) the dirty memory log for a memory slot.
1733 */ 1743 */
@@ -1925,6 +1935,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
1925 r = 0; 1935 r = 0;
1926 break; 1936 break;
1927 } 1937 }
1938 case KVM_REINJECT_CONTROL: {
1939 struct kvm_reinject_control control;
1940 r = -EFAULT;
1941 if (copy_from_user(&control, argp, sizeof(control)))
1942 goto out;
1943 r = kvm_vm_ioctl_reinject(kvm, &control);
1944 if (r)
1945 goto out;
1946 r = 0;
1947 break;
1948 }
1928 default: 1949 default:
1929 ; 1950 ;
1930 } 1951 }
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 11e3e6197c83..ae7a12c77427 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -396,6 +396,9 @@ struct kvm_trace_rec {
396#if defined(CONFIG_X86) 396#if defined(CONFIG_X86)
397#define KVM_CAP_SET_GUEST_DEBUG 23 397#define KVM_CAP_SET_GUEST_DEBUG 23
398#endif 398#endif
399#if defined(CONFIG_X86)
400#define KVM_CAP_REINJECT_CONTROL 24
401#endif
399 402
400/* 403/*
401 * ioctls for VM fds 404 * ioctls for VM fds
@@ -429,6 +432,7 @@ struct kvm_trace_rec {
429 struct kvm_assigned_pci_dev) 432 struct kvm_assigned_pci_dev)
430#define KVM_ASSIGN_IRQ _IOR(KVMIO, 0x70, \ 433#define KVM_ASSIGN_IRQ _IOR(KVMIO, 0x70, \
431 struct kvm_assigned_irq) 434 struct kvm_assigned_irq)
435#define KVM_REINJECT_CONTROL _IO(KVMIO, 0x71)
432 436
433/* 437/*
434 * ioctls for vcpu fds 438 * ioctls for vcpu fds