From patchwork Mon Jul 6 01:55:12 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marcelo Tosatti X-Patchwork-Id: 34300 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n66K1dQK005529 for ; Mon, 6 Jul 2009 20:01:40 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753961AbZGFUBe (ORCPT ); Mon, 6 Jul 2009 16:01:34 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1753952AbZGFUBd (ORCPT ); Mon, 6 Jul 2009 16:01:33 -0400 Received: from mx2.redhat.com ([66.187.237.31]:39625 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753854AbZGFUBZ (ORCPT ); Mon, 6 Jul 2009 16:01:25 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n66K1TGZ013663 for ; Mon, 6 Jul 2009 16:01:29 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n66K1R0q028824; Mon, 6 Jul 2009 16:01:28 -0400 Received: from amt.cnet (vpn-51-10.sfbay.redhat.com [10.14.51.10]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n66K1PEm030091; Mon, 6 Jul 2009 16:01:25 -0400 Received: from amt.cnet (amt.cnet [127.0.0.1]) by amt.cnet (Postfix) with ESMTP id E93276802A5; Mon, 6 Jul 2009 17:00:43 -0300 (BRT) Received: (from marcelo@localhost) by amt.cnet (8.14.3/8.14.3/Submit) id n66K0bQP008087; Mon, 6 Jul 2009 17:00:37 -0300 Message-Id: <20090706015812.465334091@localhost.localdomain> References: <20090706015511.923596553@localhost.localdomain> User-Agent: quilt/0.46-1 Date: Sun, 05 Jul 2009 22:55:12 -0300 From: Marcelo Tosatti To: kvm@vger.kernel.org Cc: Marcelo Tosatti Subject: [patch 1/8] KVM: timer interface unification Content-Disposition: inline; filename=kvm-timer-abstract X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org Hide details of timer emulation behind an interface, and unify the hrtimer based implementation. Signed-off-by: Marcelo Tosatti Index: kvm-new/arch/x86/kvm/i8254.c =================================================================== --- kvm-new.orig/arch/x86/kvm/i8254.c +++ kvm-new/arch/x86/kvm/i8254.c @@ -113,7 +113,7 @@ static s64 __kpit_elapsed(struct kvm *kv * itself with the initial count and continues counting * from there. */ - remaining = hrtimer_expires_remaining(&ps->pit_timer.timer); + remaining = kvm_timer_remaining(&ps->pit_timer); elapsed = ps->pit_timer.period - ktime_to_ns(remaining); elapsed = mod_64(elapsed, ps->pit_timer.period); @@ -229,7 +229,7 @@ int pit_has_pending_timer(struct kvm_vcp struct kvm_pit *pit = vcpu->kvm->arch.vpit; if (pit && kvm_vcpu_is_bsp(vcpu) && pit->pit_state.irq_ack) - return atomic_read(&pit->pit_state.pit_timer.pending); + return kvm_timer_has_pending(&pit->pit_state.pit_timer); return 0; } @@ -238,42 +238,17 @@ static void kvm_pit_ack_irq(struct kvm_i struct kvm_kpit_state *ps = container_of(kian, struct kvm_kpit_state, irq_ack_notifier); spin_lock(&ps->inject_lock); - if (atomic_dec_return(&ps->pit_timer.pending) < 0) - atomic_inc(&ps->pit_timer.pending); + kvm_timer_ack(&ps->pit_timer); ps->irq_ack = 1; spin_unlock(&ps->inject_lock); } -void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) -{ - struct kvm_pit *pit = vcpu->kvm->arch.vpit; - struct hrtimer *timer; - - if (!kvm_vcpu_is_bsp(vcpu) || !pit) - return; - - timer = &pit->pit_state.pit_timer.timer; - if (hrtimer_cancel(timer)) - hrtimer_start_expires(timer, HRTIMER_MODE_ABS); -} - static void destroy_pit_timer(struct kvm_timer *pt) { pr_debug("pit: execute del timer!\n"); - hrtimer_cancel(&pt->timer); + kvm_timer_cancel(pt); } -static bool kpit_is_periodic(struct kvm_timer *ktimer) -{ - struct kvm_kpit_state *ps = container_of(ktimer, struct kvm_kpit_state, - pit_timer); - return ps->is_periodic; -} - -static struct kvm_timer_ops kpit_ops = { - .is_periodic = kpit_is_periodic, -}; - static void create_pit_timer(struct kvm_kpit_state *ps, u32 val, int is_period) { struct kvm_timer *pt = &ps->pit_timer; @@ -284,20 +259,10 @@ static void create_pit_timer(struct kvm_ pr_debug("pit: create pit timer, interval is %llu nsec\n", interval); /* TODO The new value only affected after the retriggered */ - hrtimer_cancel(&pt->timer); - pt->period = interval; - ps->is_periodic = is_period; - - pt->timer.function = kvm_timer_fn; - pt->t_ops = &kpit_ops; - pt->kvm = ps->pit->kvm; - pt->vcpu = pt->kvm->bsp_vcpu; + kvm_timer_cancel(pt); - atomic_set(&pt->pending, 0); ps->irq_ack = 1; - - hrtimer_start(&pt->timer, ktime_add_ns(ktime_get(), interval), - HRTIMER_MODE_ABS); + kvm_timer_start(pt, interval, is_period); } static void pit_load_count(struct kvm *kvm, int channel, u32 val) @@ -545,7 +510,7 @@ static int speaker_ioport_read(struct kv return 0; } -void kvm_pit_reset(struct kvm_pit *pit) +static void kvm_pit_reset(struct kvm_pit *pit) { int i; struct kvm_kpit_channel_state *c; @@ -559,7 +524,7 @@ void kvm_pit_reset(struct kvm_pit *pit) } mutex_unlock(&pit->pit_state.lock); - atomic_set(&pit->pit_state.pit_timer.pending, 0); + kvm_timer_reset(&pit->pit_state.pit_timer); pit->pit_state.irq_ack = 1; } @@ -568,7 +533,7 @@ static void pit_mask_notifer(struct kvm_ struct kvm_pit *pit = container_of(kimn, struct kvm_pit, mask_notifier); if (!mask) { - atomic_set(&pit->pit_state.pit_timer.pending, 0); + kvm_timer_reset(&pit->pit_state.pit_timer); pit->pit_state.irq_ack = 1; } } @@ -608,8 +573,8 @@ struct kvm_pit *kvm_create_pit(struct kv pit_state = &pit->pit_state; pit_state->pit = pit; - hrtimer_init(&pit_state->pit_timer.timer, - CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + kvm_timer_init(kvm, &pit_state->pit_timer); + pit_state->irq_ack_notifier.gsi = 0; pit_state->irq_ack_notifier.irq_acked = kvm_pit_ack_irq; kvm_register_irq_ack_notifier(kvm, &pit_state->irq_ack_notifier); @@ -634,14 +599,11 @@ struct kvm_pit *kvm_create_pit(struct kv void kvm_free_pit(struct kvm *kvm) { - struct hrtimer *timer; - if (kvm->arch.vpit) { + kvm_timer_cancel(&kvm->arch.vpit->pit_state.pit_timer); kvm_unregister_irq_mask_notifier(kvm, 0, &kvm->arch.vpit->mask_notifier); mutex_lock(&kvm->arch.vpit->pit_state.lock); - timer = &kvm->arch.vpit->pit_state.pit_timer.timer; - hrtimer_cancel(timer); kvm_free_irq_source_id(kvm, kvm->arch.vpit->irq_source_id); mutex_unlock(&kvm->arch.vpit->pit_state.lock); kfree(kvm->arch.vpit); @@ -686,7 +648,7 @@ void kvm_inject_pit_timer_irqs(struct kv * last one has been acked. */ spin_lock(&ps->inject_lock); - if (atomic_read(&ps->pit_timer.pending) && ps->irq_ack) { + if (kvm_timer_has_pending(&ps->pit_timer) && ps->irq_ack) { ps->irq_ack = 0; inject = 1; } Index: kvm-new/arch/x86/kvm/kvm_timer.h =================================================================== --- kvm-new.orig/arch/x86/kvm/kvm_timer.h +++ kvm-new/arch/x86/kvm/kvm_timer.h @@ -1,18 +1,25 @@ struct kvm_timer { struct hrtimer timer; - s64 period; /* unit: ns */ - atomic_t pending; /* accumulated triggered timers */ + s64 period; /* unit: ns */ + atomic_t pending; /* accumulated triggered timers */ bool reinject; - struct kvm_timer_ops *t_ops; + bool periodic; struct kvm *kvm; struct kvm_vcpu *vcpu; }; -struct kvm_timer_ops { - bool (*is_periodic)(struct kvm_timer *); -}; +void kvm_timer_init(struct kvm *kvm, struct kvm_timer *ktimer); +void kvm_timer_start(struct kvm_timer *ktimer, u64 interval, bool periodic); +void kvm_timer_cancel(struct kvm_timer *ktimer); +void kvm_timer_vcpu_bind(struct kvm_timer *ktimer, struct kvm_vcpu *vcpu); + +int kvm_timer_has_pending(struct kvm_timer *ktimer); +void kvm_timer_ack(struct kvm_timer *ktimer); +void kvm_timer_reset(struct kvm_timer *ktimer); + +void kvm_migrate_timer(struct kvm_timer *ktimer); -enum hrtimer_restart kvm_timer_fn(struct hrtimer *data); +ktime_t kvm_timer_remaining(struct kvm_timer *ktimer); Index: kvm-new/arch/x86/kvm/lapic.c =================================================================== --- kvm-new.orig/arch/x86/kvm/lapic.c +++ kvm-new/arch/x86/kvm/lapic.c @@ -485,7 +485,7 @@ static u32 apic_get_tmcct(struct kvm_lap if (apic_get_reg(apic, APIC_TMICT) == 0) return 0; - remaining = hrtimer_expires_remaining(&apic->lapic_timer.timer); + remaining = kvm_timer_remaining(&apic->lapic_timer); if (ktime_to_ns(remaining) < 0) remaining = ktime_set(0, 0); @@ -601,28 +601,13 @@ static void update_divide_count(struct k static void start_apic_timer(struct kvm_lapic *apic) { - ktime_t now = apic->lapic_timer.timer.base->get_time(); - - apic->lapic_timer.period = apic_get_reg(apic, APIC_TMICT) * + u64 period = apic_get_reg(apic, APIC_TMICT) * APIC_BUS_CYCLE_NS * apic->divide_count; - atomic_set(&apic->lapic_timer.pending, 0); - if (!apic->lapic_timer.period) + if (!period) return; - hrtimer_start(&apic->lapic_timer.timer, - ktime_add_ns(now, apic->lapic_timer.period), - HRTIMER_MODE_ABS); - - apic_debug("%s: bus cycle is %" PRId64 "ns, now 0x%016" - PRIx64 ", " - "timer initial count 0x%x, period %lldns, " - "expire @ 0x%016" PRIx64 ".\n", __func__, - APIC_BUS_CYCLE_NS, ktime_to_ns(now), - apic_get_reg(apic, APIC_TMICT), - apic->lapic_timer.period, - ktime_to_ns(ktime_add_ns(now, - apic->lapic_timer.period))); + kvm_timer_start(&apic->lapic_timer, period, apic_lvtt_period(apic)); } static void apic_manage_nmi_watchdog(struct kvm_lapic *apic, u32 lvt0_val) @@ -706,8 +691,6 @@ static int apic_mmio_write(struct kvm_io apic_set_reg(apic, APIC_LVTT + 0x10 * i, lvt_val | APIC_LVT_MASKED); } - atomic_set(&apic->lapic_timer.pending, 0); - } break; @@ -738,7 +721,7 @@ static int apic_mmio_write(struct kvm_io break; case APIC_TMICT: - hrtimer_cancel(&apic->lapic_timer.timer); + kvm_timer_cancel(&apic->lapic_timer); apic_set_reg(apic, APIC_TMICT, val); start_apic_timer(apic); return 0; @@ -763,7 +746,7 @@ void kvm_free_lapic(struct kvm_vcpu *vcp if (!vcpu->arch.apic) return; - hrtimer_cancel(&vcpu->arch.apic->lapic_timer.timer); + kvm_timer_cancel(&vcpu->arch.apic->lapic_timer); if (vcpu->arch.apic->regs_page) __free_page(vcpu->arch.apic->regs_page); @@ -834,7 +817,7 @@ void kvm_lapic_reset(struct kvm_vcpu *vc ASSERT(apic != NULL); /* Stop the timer in case it's a reset to an active apic */ - hrtimer_cancel(&apic->lapic_timer.timer); + kvm_timer_cancel(&apic->lapic_timer); apic_set_reg(apic, APIC_ID, vcpu->vcpu_id << 24); apic_set_reg(apic, APIC_LVR, APIC_VERSION); @@ -860,7 +843,6 @@ void kvm_lapic_reset(struct kvm_vcpu *vc } apic->irr_pending = false; update_divide_count(apic); - atomic_set(&apic->lapic_timer.pending, 0); if (kvm_vcpu_is_bsp(vcpu)) vcpu->arch.apic_base |= MSR_IA32_APICBASE_BSP; apic_update_ppr(apic); @@ -889,19 +871,12 @@ int kvm_lapic_enabled(struct kvm_vcpu *v *---------------------------------------------------------------------- */ -static bool lapic_is_periodic(struct kvm_timer *ktimer) -{ - struct kvm_lapic *apic = container_of(ktimer, struct kvm_lapic, - lapic_timer); - return apic_lvtt_period(apic); -} - int apic_has_pending_timer(struct kvm_vcpu *vcpu) { struct kvm_lapic *lapic = vcpu->arch.apic; if (lapic && apic_enabled(lapic) && apic_lvt_enabled(lapic, APIC_LVTT)) - return atomic_read(&lapic->lapic_timer.pending); + return kvm_timer_has_pending(&lapic->lapic_timer); return 0; } @@ -928,10 +903,6 @@ void kvm_apic_nmi_wd_deliver(struct kvm_ kvm_apic_local_deliver(apic, APIC_LVT0); } -static struct kvm_timer_ops lapic_timer_ops = { - .is_periodic = lapic_is_periodic, -}; - static const struct kvm_io_device_ops apic_mmio_ops = { .read = apic_mmio_read, .write = apic_mmio_write, @@ -960,12 +931,8 @@ int kvm_create_lapic(struct kvm_vcpu *vc memset(apic->regs, 0, PAGE_SIZE); apic->vcpu = vcpu; - hrtimer_init(&apic->lapic_timer.timer, CLOCK_MONOTONIC, - HRTIMER_MODE_ABS); - apic->lapic_timer.timer.function = kvm_timer_fn; - apic->lapic_timer.t_ops = &lapic_timer_ops; - apic->lapic_timer.kvm = vcpu->kvm; - apic->lapic_timer.vcpu = vcpu; + kvm_timer_init(vcpu->kvm, &apic->lapic_timer); + kvm_timer_vcpu_bind(&apic->lapic_timer, vcpu); apic->base_address = APIC_DEFAULT_PHYS_BASE; vcpu->arch.apic_base = APIC_DEFAULT_PHYS_BASE; @@ -1015,9 +982,9 @@ void kvm_inject_apic_timer_irqs(struct k { struct kvm_lapic *apic = vcpu->arch.apic; - if (apic && atomic_read(&apic->lapic_timer.pending) > 0) { + if (apic && kvm_timer_has_pending(&apic->lapic_timer)) { if (kvm_apic_local_deliver(apic, APIC_LVTT)) - atomic_dec(&apic->lapic_timer.pending); + kvm_timer_ack(&apic->lapic_timer); } } @@ -1043,24 +1010,11 @@ void kvm_apic_post_state_restore(struct MSR_IA32_APICBASE_BASE; apic_set_reg(apic, APIC_LVR, APIC_VERSION); apic_update_ppr(apic); - hrtimer_cancel(&apic->lapic_timer.timer); + kvm_timer_cancel(&apic->lapic_timer); update_divide_count(apic); start_apic_timer(apic); } -void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) -{ - struct kvm_lapic *apic = vcpu->arch.apic; - struct hrtimer *timer; - - if (!apic) - return; - - timer = &apic->lapic_timer.timer; - if (hrtimer_cancel(timer)) - hrtimer_start_expires(timer, HRTIMER_MODE_ABS); -} - void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu) { u32 data; Index: kvm-new/arch/x86/kvm/timer.c =================================================================== --- kvm-new.orig/arch/x86/kvm/timer.c +++ kvm-new/arch/x86/kvm/timer.c @@ -23,7 +23,7 @@ static int __kvm_timer_fn(struct kvm_vcp if (waitqueue_active(q)) wake_up_interruptible(q); - if (ktimer->t_ops->is_periodic(ktimer)) { + if (ktimer->periodic) { hrtimer_add_expires_ns(&ktimer->timer, ktimer->period); restart_timer = 1; } @@ -31,7 +31,7 @@ static int __kvm_timer_fn(struct kvm_vcp return restart_timer; } -enum hrtimer_restart kvm_timer_fn(struct hrtimer *data) +static enum hrtimer_restart kvm_timer_fn(struct hrtimer *data) { int restart_timer; struct kvm_vcpu *vcpu; @@ -48,3 +48,58 @@ enum hrtimer_restart kvm_timer_fn(struct return HRTIMER_NORESTART; } +void kvm_timer_init(struct kvm *kvm, struct kvm_timer *ktimer) +{ + ktimer->kvm = kvm; + hrtimer_init(&ktimer->timer, CLOCK_MONOTONIC, HRTIMER_MODE_ABS); + ktimer->timer.function = kvm_timer_fn; +} + +void kvm_timer_vcpu_bind(struct kvm_timer *ktimer, struct kvm_vcpu *vcpu) +{ + ktimer->vcpu = vcpu; +} + +void kvm_timer_start(struct kvm_timer *ktimer, u64 interval, bool periodic) +{ + hrtimer_cancel(&ktimer->timer); + atomic_set(&ktimer->pending, 0); + ktimer->periodic = periodic; + ktimer->period = interval; + hrtimer_start(&ktimer->timer, ktime_add_ns(ktime_get(), interval), + HRTIMER_MODE_ABS); +} + +void kvm_timer_cancel(struct kvm_timer *ktimer) +{ + hrtimer_cancel(&ktimer->timer); + atomic_set(&ktimer->pending, 0); +} + +int kvm_timer_has_pending(struct kvm_timer *ktimer) +{ + return atomic_read(&ktimer->pending); +} + +void kvm_timer_ack(struct kvm_timer *ktimer) +{ + if (atomic_dec_return(&ktimer->pending) < 0) + atomic_inc(&ktimer->pending); +} + +void kvm_timer_reset(struct kvm_timer *ktimer) +{ + atomic_set(&ktimer->pending, 0); +} + +void kvm_migrate_timer(struct kvm_timer *ktimer) +{ + if (hrtimer_cancel(&ktimer->timer)) + hrtimer_start_expires(&ktimer->timer, HRTIMER_MODE_ABS); +} + +ktime_t kvm_timer_remaining(struct kvm_timer *ktimer) +{ + return hrtimer_expires_remaining(&ktimer->timer); +} + Index: kvm-new/arch/x86/kvm/i8254.h =================================================================== --- kvm-new.orig/arch/x86/kvm/i8254.h +++ kvm-new/arch/x86/kvm/i8254.h @@ -22,7 +22,6 @@ struct kvm_kpit_channel_state { struct kvm_kpit_state { struct kvm_kpit_channel_state channels[3]; struct kvm_timer pit_timer; - bool is_periodic; u32 speaker_data_on; struct mutex lock; struct kvm_pit *pit; @@ -52,6 +51,5 @@ void kvm_inject_pit_timer_irqs(struct kv void kvm_pit_load_count(struct kvm *kvm, int channel, u32 val); struct kvm_pit *kvm_create_pit(struct kvm *kvm, u32 flags); void kvm_free_pit(struct kvm *kvm); -void kvm_pit_reset(struct kvm_pit *pit); #endif Index: kvm-new/arch/x86/kvm/irq.c =================================================================== --- kvm-new.orig/arch/x86/kvm/irq.c +++ kvm-new/arch/x86/kvm/irq.c @@ -94,6 +94,26 @@ void kvm_inject_pending_timer_irqs(struc } EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs); +static void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu) +{ + struct kvm_lapic *apic = vcpu->arch.apic; + + if (!apic) + return; + + kvm_migrate_timer(&apic->lapic_timer); +} + +static void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu) +{ + struct kvm_pit *pit = vcpu->kvm->arch.vpit; + + if (!kvm_vcpu_is_bsp(vcpu) || !pit) + return; + + kvm_migrate_timer(&pit->pit_state.pit_timer); +} + void __kvm_migrate_timers(struct kvm_vcpu *vcpu) { __kvm_migrate_apic_timer(vcpu); Index: kvm-new/arch/x86/kvm/irq.h =================================================================== --- kvm-new.orig/arch/x86/kvm/irq.h +++ kvm-new/arch/x86/kvm/irq.h @@ -94,8 +94,6 @@ void kvm_pic_reset(struct kvm_kpic_state void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu); void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu); void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu); -void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu); -void __kvm_migrate_pit_timer(struct kvm_vcpu *vcpu); void __kvm_migrate_timers(struct kvm_vcpu *vcpu); int pit_has_pending_timer(struct kvm_vcpu *vcpu); Index: kvm-new/arch/x86/kvm/x86.c =================================================================== --- kvm-new.orig/arch/x86/kvm/x86.c +++ kvm-new/arch/x86/kvm/x86.c @@ -4565,6 +4565,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(st int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu) { int r; + struct kvm *kvm = vcpu->kvm; /* We do fxsave: this must be aligned. */ BUG_ON((unsigned long)&vcpu->arch.host_fx_image & 0xF); @@ -4578,6 +4579,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu if (r < 0) goto free_vcpu; + if (kvm->arch.vpit && kvm_vcpu_is_bsp(vcpu)) + kvm_timer_vcpu_bind(&kvm->arch.vpit->pit_state.pit_timer, vcpu); + return 0; free_vcpu: kvm_x86_ops->vcpu_free(vcpu);