diff options
author | Marcelo Tosatti <mtosatti@redhat.com> | 2009-02-23 08:57:41 -0500 |
---|---|---|
committer | Avi Kivity <avi@redhat.com> | 2009-06-10 04:48:25 -0400 |
commit | d3c7b77d1a6e7a0a27035a7ba723a3455317883e (patch) | |
tree | 65053ca8122dda5772c48ce70c9d99e8127f8cdd /arch | |
parent | fd66842370e32f3bbe429677280a326c07e508c1 (diff) |
KVM: unify part of generic timer handling
Hide the internals of vcpu awakening / injection from the in-kernel
emulated timers. This makes future changes in this logic easier and
decreases the distance to more generic timer handling.
Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/x86/kvm/Makefile | 2 | ||||
-rw-r--r-- | arch/x86/kvm/i8254.c | 57 | ||||
-rw-r--r-- | arch/x86/kvm/i8254.h | 11 | ||||
-rw-r--r-- | arch/x86/kvm/kvm_timer.h | 18 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.c | 94 | ||||
-rw-r--r-- | arch/x86/kvm/lapic.h | 9 | ||||
-rw-r--r-- | arch/x86/kvm/timer.c | 46 |
7 files changed, 129 insertions, 108 deletions
diff --git a/arch/x86/kvm/Makefile b/arch/x86/kvm/Makefile index d3ec292f00f..b43c4efafe8 100644 --- a/arch/x86/kvm/Makefile +++ b/arch/x86/kvm/Makefile | |||
@@ -14,7 +14,7 @@ endif | |||
14 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm | 14 | EXTRA_CFLAGS += -Ivirt/kvm -Iarch/x86/kvm |
15 | 15 | ||
16 | kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \ | 16 | kvm-objs := $(common-objs) x86.o mmu.o x86_emulate.o i8259.o irq.o lapic.o \ |
17 | i8254.o | 17 | i8254.o timer.o |
18 | obj-$(CONFIG_KVM) += kvm.o | 18 | obj-$(CONFIG_KVM) += kvm.o |
19 | kvm-intel-objs = vmx.o | 19 | kvm-intel-objs = vmx.o |
20 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o | 20 | obj-$(CONFIG_KVM_INTEL) += kvm-intel.o |
diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c index 09ae841ff46..4e2e3f26dbf 100644 --- a/arch/x86/kvm/i8254.c +++ b/arch/x86/kvm/i8254.c | |||
@@ -219,25 +219,6 @@ static void pit_latch_status(struct kvm *kvm, int channel) | |||
219 | } | 219 | } |
220 | } | 220 | } |
221 | 221 | ||
222 | static int __pit_timer_fn(struct kvm_kpit_state *ps) | ||
223 | { | ||
224 | struct kvm_vcpu *vcpu0 = ps->pit->kvm->vcpus[0]; | ||
225 | struct kvm_kpit_timer *pt = &ps->pit_timer; | ||
226 | |||
227 | if (!atomic_inc_and_test(&pt->pending)) | ||
228 | set_bit(KVM_REQ_PENDING_TIMER, &vcpu0->requests); | ||
229 | |||
230 | if (!pt->reinject) | ||
231 | atomic_set(&pt->pending, 1); | ||
232 | |||
233 | if (vcpu0 && waitqueue_active(&vcpu0->wq)) | ||
234 | wake_up_interruptible(&vcpu0->wq); | ||
235 | |||
236 | hrtimer_add_expires_ns(&pt->timer, pt->period); | ||
237 | |||
238 | return (pt->period == 0 ? 0 : 1); | ||
239 | } | ||
240 | |||
241 | int pit_has_pending_timer(struct kvm_vcpu *vcpu) | 222 | int pit_has_pending_timer(struct kvm_vcpu *vcpu) |
242 | { | 223 | { |
243 | struct kvm_pit *pit = vcpu->kvm->arch.vpit; | 224 | struct kvm_pit *pit = vcpu->kvm->arch.vpit; |
@@ -258,21 +239,6 @@ static void kvm_pit_ack_irq(struct kvm_irq_ack_notifier *kian) | |||
258 | spin_unlock(&ps->inject_lock); | 239 | spin_unlock(&ps->inject_lock); |
259 | } | 240 | } |
260 | 241 | ||
261 | static enum hrtimer_restart pit_timer_fn(struct hrtimer *data) | ||
262 | { | ||
263 | struct kvm_kpit_state *ps; | ||
264 | int restart_timer = 0; | ||
265 | |||
266 | ps = container_of(data, struct kvm_kpit_state, pit_timer.timer); | ||
267 | |||
268 | restart_timer = __pit_timer_fn(ps); | ||
269 | |||
270 | if (restart_timer) | ||
271 | return HRTIMER_RESTART; | ||
272 | else | ||
273 | return HRTIMER_NORESTART; | ||
274 | } | ||
275 | |||
276 | void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) | 242 | void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) |
277 | { | 243 | { |
278 | struct kvm_pit *pit = vcpu->kvm->arch.vpit; | 244 | struct kvm_pit *pit = vcpu->kvm->arch.vpit; |
@@ -286,15 +252,26 @@ void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) | |||
286 | hrtimer_start_expires(timer, HRTIMER_MODE_ABS); | 252 | hrtimer_start_expires(timer, HRTIMER_MODE_ABS); |
287 | } | 253 | } |
288 | 254 | ||
289 | static void destroy_pit_timer(struct kvm_kpit_timer *pt) | 255 | static void destroy_pit_timer(struct kvm_timer *pt) |
290 | { | 256 | { |
291 | pr_debug("pit: execute del timer!\n"); | 257 | pr_debug("pit: execute del timer!\n"); |
292 | hrtimer_cancel(&pt->timer); | 258 | hrtimer_cancel(&pt->timer); |
293 | } | 259 | } |
294 | 260 | ||
261 | static bool kpit_is_periodic(struct kvm_timer *ktimer) | ||
262 | { | ||
263 | struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state, | ||
264 | pit_timer); | ||
265 | return ps->is_periodic; | ||
266 | } | ||
267 | |||
268 | struct kvm_timer_ops kpit_ops = { | ||
269 | .is_periodic = kpit_is_periodic, | ||
270 | }; | ||
271 | |||
295 | static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period) | 272 | static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period) |
296 | { | 273 | { |
297 | struct kvm_kpit_timer *pt = &ps->pit_timer; | 274 | struct kvm_timer *pt = &ps->pit_timer; |
298 | s64 interval; | 275 | s64 interval; |
299 | 276 | ||
300 | interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ); | 277 | interval = muldiv64(val, NSEC_PER_SEC, KVM_PIT_FREQ); |
@@ -304,7 +281,13 @@ static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period) | |||
304 | /* TODO The new value only affected after the retriggered */ | 281 | /* TODO The new value only affected after the retriggered */ |
305 | hrtimer_cancel(&pt->timer); | 282 | hrtimer_cancel(&pt->timer); |
306 | pt->period = (is_period == 0) ? 0 : interval; | 283 | pt->period = (is_period == 0) ? 0 : interval; |
307 | pt->timer.function = pit_timer_fn; | 284 | ps->is_periodic = is_period; |
285 | |||
286 | pt->timer.function = kvm_timer_fn; | ||
287 | pt->t_ops = &kpit_ops; | ||
288 | pt->kvm = ps->pit->kvm; | ||
289 | pt->vcpu_id = 0; | ||
290 | |||
308 | atomic_set(&pt->pending, 0); | 291 | atomic_set(&pt->pending, 0); |
309 | ps->irq_ack = 1; | 292 | ps->irq_ack = 1; |
310 | 293 | ||
diff --git a/arch/x86/kvm/i8254.h b/arch/x86/kvm/i8254.h index 521accf3bae..bbd863ff60b 100644 --- a/arch/x86/kvm/i8254.h +++ b/arch/x86/kvm/i8254.h | |||
@@ -3,14 +3,6 @@ | |||
3 | 3 | ||
4 | #include "iodev.h" | 4 | #include "iodev.h" |
5 | 5 | ||
6 | struct kvm_kpit_timer { | ||
7 | struct hrtimer timer; | ||
8 | int irq; | ||
9 | s64 period; /* unit: ns */ | ||
10 | atomic_t pending; | ||
11 | bool reinject; | ||
12 | }; | ||
13 | |||
14 | struct kvm_kpit_channel_state { | 6 | struct kvm_kpit_channel_state { |
15 | u32 count; /* can be 65536 */ | 7 | u32 count; /* can be 65536 */ |
16 | u16 latched_count; | 8 | u16 latched_count; |
@@ -29,7 +21,8 @@ struct kvm_kpit_channel_state { | |||
29 | 21 | ||
30 | struct kvm_kpit_state { | 22 | struct kvm_kpit_state { |
31 | struct kvm_kpit_channel_state channels[3]; | 23 | struct kvm_kpit_channel_state channels[3]; |
32 | struct kvm_kpit_timer pit_timer; | 24 | struct kvm_timer pit_timer; |
25 | bool is_periodic; | ||
33 | u32 speaker_data_on; | 26 | u32 speaker_data_on; |
34 | struct mutex lock; | 27 | struct mutex lock; |
35 | struct kvm_pit *pit; | 28 | struct kvm_pit *pit; |
diff --git a/arch/x86/kvm/kvm_timer.h b/arch/x86/kvm/kvm_timer.h new file mode 100644 index 00000000000..26bd6ba74e1 --- /dev/null +++ b/arch/x86/kvm/kvm_timer.h | |||
@@ -0,0 +1,18 @@ | |||
1 | |||
2 | struct kvm_timer { | ||
3 | struct hrtimer timer; | ||
4 | s64 period; /* unit: ns */ | ||
5 | atomic_t pending; /* accumulated triggered timers */ | ||
6 | bool reinject; | ||
7 | struct kvm_timer_ops *t_ops; | ||
8 | struct kvm *kvm; | ||
9 | int vcpu_id; | ||
10 | }; | ||
11 | |||
12 | struct kvm_timer_ops { | ||
13 | bool (*is_periodic)(struct kvm_timer *); | ||
14 | }; | ||
15 | |||
16 | |||
17 | enum hrtimer_restart kvm_timer_fn(struct hrtimer *data); | ||
18 | |||
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c index afc59b2e7e0..27ca43e4e44 100644 --- a/arch/x86/kvm/lapic.c +++ b/arch/x86/kvm/lapic.c | |||
@@ -528,12 +528,13 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic) | |||
528 | if (apic_get_reg(apic, APIC_TMICT) == 0) | 528 | if (apic_get_reg(apic, APIC_TMICT) == 0) |
529 | return 0; | 529 | return 0; |
530 | 530 | ||
531 | remaining = hrtimer_expires_remaining(&apic->timer.dev); | 531 | remaining = hrtimer_expires_remaining(&apic->lapic_timer.timer); |
532 | if (ktime_to_ns(remaining) < 0) | 532 | if (ktime_to_ns(remaining) < 0) |
533 | remaining = ktime_set(0, 0); | 533 | remaining = ktime_set(0, 0); |
534 | 534 | ||
535 | ns = mod_64(ktime_to_ns(remaining), apic->timer.period); | 535 | ns = mod_64(ktime_to_ns(remaining), apic->lapic_timer.period); |
536 | tmcct = div64_u64(ns, (APIC_BUS_CYCLE_NS * apic->timer.divide_count)); | 536 | tmcct = div64_u64(ns, |
537 | (APIC_BUS_CYCLE_NS * apic->divide_count)); | ||
537 | 538 | ||
538 | return tmcct; | 539 | return tmcct; |
539 | } | 540 | } |
@@ -620,25 +621,25 @@ static void update_divide_count(struct kvm_lapic *apic) | |||
620 | tdcr = apic_get_reg(apic, APIC_TDCR); | 621 | tdcr = apic_get_reg(apic, APIC_TDCR); |
621 | tmp1 = tdcr & 0xf; | 622 | tmp1 = tdcr & 0xf; |
622 | tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; | 623 | tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1; |
623 | apic->timer.divide_count = 0x1 << (tmp2 & 0x7); | 624 | apic->divide_count = 0x1 << (tmp2 & 0x7); |
624 | 625 | ||
625 | apic_debug("timer divide count is 0x%x\n", | 626 | apic_debug("timer divide count is 0x%x\n", |
626 | apic->timer.divide_count); | 627 | apic->lapic_timer.divide_count); |
627 | } | 628 | } |
628 | 629 | ||
629 | static void start_apic_timer(struct kvm_lapic *apic) | 630 | static void start_apic_timer(struct kvm_lapic *apic) |
630 | { | 631 | { |
631 | ktime_t now = apic->timer.dev.base->get_time(); | 632 | ktime_t now = apic->lapic_timer.timer.base->get_time(); |
632 | 633 | ||
633 | apic->timer.period = apic_get_reg(apic, APIC_TMICT) * | 634 | apic->lapic_timer.period = apic_get_reg(apic, APIC_TMICT) * |
634 | APIC_BUS_CYCLE_NS * apic->timer.divide_count; | 635 | APIC_BUS_CYCLE_NS * apic->divide_count; |
635 | atomic_set(&apic->timer.pending, 0); | 636 | atomic_set(&apic->lapic_timer.pending, 0); |
636 | 637 | ||
637 | if (!apic->timer.period) | 638 | if (!apic->lapic_timer.period) |
638 | return; | 639 | return; |
639 | 640 | ||
640 | hrtimer_start(&apic->timer.dev, | 641 | hrtimer_start(&apic->lapic_timer.timer, |
641 | ktime_add_ns(now, apic->timer.period), | 642 | ktime_add_ns(now, apic->lapic_timer.period), |
642 | HRTIMER_MODE_ABS); | 643 | HRTIMER_MODE_ABS); |
643 | 644 | ||
644 | apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" | 645 | apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" |
@@ -647,9 +648,9 @@ static void start_apic_timer(struct kvm_lapic *apic) | |||
647 | "expire @ 0x%016" PRIx64 ".\n", __func__, | 648 | "expire @ 0x%016" PRIx64 ".\n", __func__, |
648 | APIC_BUS_CYCLE_NS, ktime_to_ns(now), | 649 | APIC_BUS_CYCLE_NS, ktime_to_ns(now), |
649 | apic_get_reg(apic, APIC_TMICT), | 650 | apic_get_reg(apic, APIC_TMICT), |
650 | apic->timer.period, | 651 | apic->lapic_timer.period, |
651 | ktime_to_ns(ktime_add_ns(now, | 652 | ktime_to_ns(ktime_add_ns(now, |
652 | apic->timer.period))); | 653 | apic->lapic_timer.period))); |
653 | } | 654 | } |
654 | 655 | ||
655 | static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) | 656 | static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) |
@@ -731,7 +732,7 @@ static void apic_mmio_write(struct kvm_io_device *this, | |||
731 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, | 732 | apic_set_reg(apic, APIC_LVTT + 0x10 * i, |
732 | lvt_val | APIC_LVT_MASKED); | 733 | lvt_val | APIC_LVT_MASKED); |
733 | } | 734 | } |
734 | atomic_set(&apic->timer.pending, 0); | 735 | atomic_set(&apic->lapic_timer.pending, 0); |
735 | 736 | ||
736 | } | 737 | } |
737 | break; | 738 | break; |
@@ -763,7 +764,7 @@ static void apic_mmio_write(struct kvm_io_device *this, | |||
763 | break; | 764 | break; |
764 | 765 | ||
765 | case APIC_TMICT: | 766 | case APIC_TMICT: |
766 | hrtimer_cancel(&apic->timer.dev); | 767 | hrtimer_cancel(&apic->lapic_timer.timer); |
767 | apic_set_reg(apic, APIC_TMICT, val); | 768 | apic_set_reg(apic, APIC_TMICT, val); |
768 | start_apic_timer(apic); | 769 | start_apic_timer(apic); |
769 | return; | 770 | return; |
@@ -803,7 +804,7 @@ void kvm_free_lapic(struct kvm_vcpu *vcpu) | |||
803 | if (!vcpu->arch.apic) | 804 | if (!vcpu->arch.apic) |
804 | return; | 805 | return; |
805 | 806 | ||
806 | hrtimer_cancel(&vcpu->arch.apic->timer.dev); | 807 | hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer); |
807 | 808 | ||
808 | if (vcpu->arch.apic->regs_page) | 809 | if (vcpu->arch.apic->regs_page) |
809 | __free_page(vcpu->arch.apic->regs_page); | 810 | __free_page(vcpu->arch.apic->regs_page); |
@@ -881,7 +882,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) | |||
881 | ASSERT(apic != NULL); | 882 | ASSERT(apic != NULL); |
882 | 883 | ||
883 | /* Stop the timer in case it's a reset to an active apic */ | 884 | /* Stop the timer in case it's a reset to an active apic */ |
884 | hrtimer_cancel(&apic->timer.dev); | 885 | hrtimer_cancel(&apic->lapic_timer.timer); |
885 | 886 | ||
886 | apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); | 887 | apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); |
887 | apic_set_reg(apic, APIC_LVR, APIC_VERSION); | 888 | apic_set_reg(apic, APIC_LVR, APIC_VERSION); |
@@ -906,7 +907,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vcpu) | |||
906 | apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); | 907 | apic_set_reg(apic, APIC_TMR + 0x10 * i, 0); |
907 | } | 908 | } |
908 | update_divide_count(apic); | 909 | update_divide_count(apic); |
909 | atomic_set(&apic->timer.pending, 0); | 910 | atomic_set(&apic->lapic_timer.pending, 0); |
910 | if (vcpu->vcpu_id == 0) | 911 | if (vcpu->vcpu_id == 0) |
911 | vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP; | 912 | vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP; |
912 | apic_update_ppr(apic); | 913 | apic_update_ppr(apic); |
@@ -937,22 +938,11 @@ EXPORT_SYMBOL_GPL(kvm_lapic_enabled); | |||
937 | *---------------------------------------------------------------------- | 938 | *---------------------------------------------------------------------- |
938 | */ | 939 | */ |
939 | 940 | ||
940 | /* TODO: make sure __apic_timer_fn runs in current pCPU */ | 941 | static bool lapic_is_periodic(struct kvm_timer *ktimer) |
941 | static int __apic_timer_fn(struct kvm_lapic *apic) | ||
942 | { | 942 | { |
943 | int result = 0; | 943 | struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic, |
944 | wait_queue_head_t *q = &apic->vcpu->wq; | 944 | lapic_timer); |
945 | 945 | return apic_lvtt_period(apic); | |
946 | if(!atomic_inc_and_test(&apic->timer.pending)) | ||
947 | set_bit(KVM_REQ_PENDING_TIMER, &apic->vcpu->requests); | ||
948 | if (waitqueue_active(q)) | ||
949 | wake_up_interruptible(q); | ||
950 | |||
951 | if (apic_lvtt_period(apic)) { | ||
952 | result = 1; | ||
953 | hrtimer_add_expires_ns(&apic->timer.dev, apic->timer.period); | ||
954 | } | ||
955 | return result; | ||
956 | } | 946 | } |
957 | 947 | ||
958 | int apic_has_pending_timer(struct kvm_vcpu *vcpu) | 948 | int apic_has_pending_timer(struct kvm_vcpu *vcpu) |
@@ -960,7 +950,7 @@ int apic_has_pending_timer(struct kvm_vcpu *vcpu) | |||
960 | struct kvm_lapic *lapic = vcpu->arch.apic; | 950 | struct kvm_lapic *lapic = vcpu->arch.apic; |
961 | 951 | ||
962 | if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT)) | 952 | if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT)) |
963 | return atomic_read(&lapic->timer.pending); | 953 | return atomic_read(&lapic->lapic_timer.pending); |
964 | 954 | ||
965 | return 0; | 955 | return 0; |
966 | } | 956 | } |
@@ -987,20 +977,9 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu) | |||
987 | kvm_apic_local_deliver(apic, APIC_LVT0); | 977 | kvm_apic_local_deliver(apic, APIC_LVT0); |
988 | } | 978 | } |
989 | 979 | ||
990 | static enum hrtimer_restart apic_timer_fn(struct hrtimer *data) | 980 | struct kvm_timer_ops lapic_timer_ops = { |
991 | { | 981 | .is_periodic = lapic_is_periodic, |
992 | struct kvm_lapic *apic; | 982 | }; |
993 | int restart_timer = 0; | ||
994 | |||
995 | apic = container_of(data, struct kvm_lapic, timer.dev); | ||
996 | |||
997 | restart_timer = __apic_timer_fn(apic); | ||
998 | |||
999 | if (restart_timer) | ||
1000 | return HRTIMER_RESTART; | ||
1001 | else | ||
1002 | return HRTIMER_NORESTART; | ||
1003 | } | ||
1004 | 983 | ||
1005 | int kvm_create_lapic(struct kvm_vcpu *vcpu) | 984 | int kvm_create_lapic(struct kvm_vcpu *vcpu) |
1006 | { | 985 | { |
@@ -1025,8 +1004,13 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu) | |||
1025 | memset(apic->regs, 0, PAGE_SIZE); | 1004 | memset(apic->regs, 0, PAGE_SIZE); |
1026 | apic->vcpu = vcpu; | 1005 | apic->vcpu = vcpu; |
1027 | 1006 | ||
1028 | hrtimer_init(&apic->timer.dev, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); | 1007 | hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, |
1029 | apic->timer.dev.function = apic_timer_fn; | 1008 | HRTIMER_MODE_ABS); |
1009 | apic->lapic_timer.timer.function = kvm_timer_fn; | ||
1010 | apic->lapic_timer.t_ops = &lapic_timer_ops; | ||
1011 | apic->lapic_timer.kvm = vcpu->kvm; | ||
1012 | apic->lapic_timer.vcpu_id = vcpu->vcpu_id; | ||
1013 | |||
1030 | apic->base_address = APIC_DEFAULT_PHYS_BASE; | 1014 | apic->base_address = APIC_DEFAULT_PHYS_BASE; |
1031 | vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE; | 1015 | vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE; |
1032 | 1016 | ||
@@ -1079,9 +1063,9 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu) | |||
1079 | { | 1063 | { |
1080 | struct kvm_lapic *apic = vcpu->arch.apic; | 1064 | struct kvm_lapic *apic = vcpu->arch.apic; |
1081 | 1065 | ||
1082 | if (apic && atomic_read(&apic->timer.pending) > 0) { | 1066 | if (apic && atomic_read(&apic->lapic_timer.pending) > 0) { |
1083 | if (kvm_apic_local_deliver(apic, APIC_LVTT)) | 1067 | if (kvm_apic_local_deliver(apic, APIC_LVTT)) |
1084 | atomic_dec(&apic->timer.pending); | 1068 | atomic_dec(&apic->lapic_timer.pending); |
1085 | } | 1069 | } |
1086 | } | 1070 | } |
1087 | 1071 | ||
@@ -1107,7 +1091,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu) | |||
1107 | MSR_IA32_APICBASE_BASE; | 1091 | MSR_IA32_APICBASE_BASE; |
1108 | apic_set_reg(apic, APIC_LVR, APIC_VERSION); | 1092 | apic_set_reg(apic, APIC_LVR, APIC_VERSION); |
1109 | apic_update_ppr(apic); | 1093 | apic_update_ppr(apic); |
1110 | hrtimer_cancel(&apic->timer.dev); | 1094 | hrtimer_cancel(&apic->lapic_timer.timer); |
1111 | update_divide_count(apic); | 1095 | update_divide_count(apic); |
1112 | start_apic_timer(apic); | 1096 | start_apic_timer(apic); |
1113 | } | 1097 | } |
@@ -1120,7 +1104,7 @@ void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) | |||
1120 | if (!apic) | 1104 | if (!apic) |
1121 | return; | 1105 | return; |
1122 | 1106 | ||
1123 | timer = &apic->timer.dev; | 1107 | timer = &apic->lapic_timer.timer; |
1124 | if (hrtimer_cancel(timer)) | 1108 | if (hrtimer_cancel(timer)) |
1125 | hrtimer_start_expires(timer, HRTIMER_MODE_ABS); | 1109 | hrtimer_start_expires(timer, HRTIMER_MODE_ABS); |
1126 | } | 1110 | } |
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h index 45ab6ee7120..2fc0d3c1b19 100644 --- a/arch/x86/kvm/lapic.h +++ b/arch/x86/kvm/lapic.h | |||
@@ -2,18 +2,15 @@ | |||
2 | #define __KVM_X86_LAPIC_H | 2 | #define __KVM_X86_LAPIC_H |
3 | 3 | ||
4 | #include "iodev.h" | 4 | #include "iodev.h" |
5 | #include "kvm_timer.h" | ||
5 | 6 | ||
6 | #include <linux/kvm_host.h> | 7 | #include <linux/kvm_host.h> |
7 | 8 | ||
8 | struct kvm_lapic { | 9 | struct kvm_lapic { |
9 | unsigned long base_address; | 10 | unsigned long base_address; |
10 | struct kvm_io_device dev; | 11 | struct kvm_io_device dev; |
11 | struct { | 12 | struct kvm_timer lapic_timer; |
12 | atomic_t pending; | 13 | u32 divide_count; |
13 | s64 period; /* unit: ns */ | ||
14 | u32 divide_count; | ||
15 | struct hrtimer dev; | ||
16 | } timer; | ||
17 | struct kvm_vcpu *vcpu; | 14 | struct kvm_vcpu *vcpu; |
18 | struct page *regs_page; | 15 | struct page *regs_page; |
19 | void *regs; | 16 | void *regs; |
diff --git a/arch/x86/kvm/timer.c b/arch/x86/kvm/timer.c new file mode 100644 index 00000000000..86dbac072d0 --- /dev/null +++ b/arch/x86/kvm/timer.c | |||
@@ -0,0 +1,46 @@ | |||
1 | #include <linux/kvm_host.h> | ||
2 | #include <linux/kvm.h> | ||
3 | #include <linux/hrtimer.h> | ||
4 | #include <asm/atomic.h> | ||
5 | #include "kvm_timer.h" | ||
6 | |||
7 | static int __kvm_timer_fn(struct kvm_vcpu *vcpu, struct kvm_timer *ktimer) | ||
8 | { | ||
9 | int restart_timer = 0; | ||
10 | wait_queue_head_t *q = &vcpu->wq; | ||
11 | |||
12 | /* FIXME: this code should not know anything about vcpus */ | ||
13 | if (!atomic_inc_and_test(&ktimer->pending)) | ||
14 | set_bit(KVM_REQ_PENDING_TIMER, &vcpu->requests); | ||
15 | |||
16 | if (!ktimer->reinject) | ||
17 | atomic_set(&ktimer->pending, 1); | ||
18 | |||
19 | if (waitqueue_active(q)) | ||
20 | wake_up_interruptible(q); | ||
21 | |||
22 | if (ktimer->t_ops->is_periodic(ktimer)) { | ||
23 | hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); | ||
24 | restart_timer = 1; | ||
25 | } | ||
26 | |||
27 | return restart_timer; | ||
28 | } | ||
29 | |||
30 | enum hrtimer_restart kvm_timer_fn(struct hrtimer *data) | ||
31 | { | ||
32 | int restart_timer; | ||
33 | struct kvm_vcpu *vcpu; | ||
34 | struct kvm_timer *ktimer = container_of(data, struct kvm_timer, timer); | ||
35 | |||
36 | vcpu = ktimer->kvm->vcpus[ktimer->vcpu_id]; | ||
37 | if (!vcpu) | ||
38 | return HRTIMER_NORESTART; | ||
39 | |||
40 | restart_timer = __kvm_timer_fn(vcpu, ktimer); | ||
41 | if (restart_timer) | ||
42 | return HRTIMER_RESTART; | ||
43 | else | ||
44 | return HRTIMER_NORESTART; | ||
45 | } | ||
46 | |||