/* * 8253/8254 interval timer emulation * * Copyright (c) 2003-2004 Fabrice Bellard * Copyright (c) 2006 Intel Corporation * Copyright (c) 2007 Keir Fraser, XenSource Inc * Copyright (c) 2008 Intel Corporation * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Authors: * Sheng Yang <sheng.yang@intel.com> * Based on QEMU and Xen.
*/
switch (c->mode) { default: case 0: case 4: /* XXX: just disable/enable counting */ break; case 1: case 2: case 3: case 5: /* Restart counting on rising edge. */ if (c->gate < val)
c->count_load_time = ktime_get(); break;
}
c->gate = val;
}
staticint pit_get_gate(struct kvm_pit *pit, int channel)
{ return pit->pit_state.channels[channel].gate;
}
/* * The Counter does not stop when it reaches zero. In * Modes 0, 1, 4, and 5 the Counter ``wraps around'' to * the highest count, either FFFF hex for binary counting * or 9999 for BCD counting, and continues counting. * Modes 2 and 3 are periodic; the Counter reloads * itself with the initial count and continues counting * from there.
*/
remaining = hrtimer_get_remaining(&ps->timer);
elapsed = ps->period - ktime_to_ns(remaining);
return elapsed;
}
static s64 kpit_elapsed(struct kvm_pit *pit, struct kvm_kpit_channel_state *c, int channel)
{ if (channel == 0) return __kpit_elapsed(pit);
atomic_set(&ps->irq_ack, 1); /* irq_ack should be set before pending is read. Order accesses with * inc(pending) in pit_timer_fn and xchg(irq_ack, 0) in pit_do_work.
*/
smp_mb(); if (atomic_dec_if_positive(&ps->pending) > 0)
kthread_queue_work(pit->worker, &pit->expired);
}
/* * Provides NMI watchdog support via Virtual Wire mode. * The route is: PIT -> LVT0 in NMI mode. * * Note: Our Virtual Wire implementation does not follow * the MP specification. We propagate a PIT interrupt to all * VCPUs and only when LVT0 is in NMI mode. The interrupt can * also be simultaneously delivered through PIC and IOAPIC.
*/ if (atomic_read(&kvm->arch.vapics_in_nmi_mode) > 0)
kvm_for_each_vcpu(i, vcpu, kvm)
kvm_apic_nmi_wd_deliver(vcpu);
}
if (atomic_read(&ps->reinject) == reinject) return;
/* * AMD SVM AVIC accelerates EOI write and does not trap. * This cause in-kernel PIT re-inject mode to fail * since it checks ps->irq_ack before kvm_set_irq() * and relies on the ack notifier to timely queue * the pt->worker work iterm and reinject the missed tick. * So, deactivate APICv when PIT is in reinject mode.
*/ if (reinject) {
kvm_set_apicv_inhibit(kvm, APICV_INHIBIT_REASON_PIT_REINJ); /* The initial state is preserved while ps->reinject == 0. */
kvm_pit_reset_reinject(pit);
kvm_register_irq_ack_notifier(kvm, &ps->irq_ack_notifier);
kvm_register_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
} else {
kvm_clear_apicv_inhibit(kvm, APICV_INHIBIT_REASON_PIT_REINJ);
kvm_unregister_irq_ack_notifier(kvm, &ps->irq_ack_notifier);
kvm_unregister_irq_mask_notifier(kvm, 0, &pit->mask_notifier);
}
pr_debug("create pit timer, interval is %llu nsec\n", interval);
/* TODO The new value only affected after the retriggered */
hrtimer_cancel(&ps->timer);
kthread_flush_work(&pit->expired);
ps->period = interval;
ps->is_periodic = is_period;
kvm_pit_reset_reinject(pit);
/* * Do not allow the guest to program periodic timers with small * interval, since the hrtimers are not throttled by the host * scheduler.
*/ if (ps->is_periodic) {
s64 min_period = min_timer_period_us * 1000LL;
if (ps->period < min_period) {
pr_info_ratelimited( "requested %lld ns " "i8254 timer period limited to %lld ns\n",
ps->period, min_period);
ps->period = min_period;
}
}
pr_debug("load_count val is %u, channel is %d\n", val, channel);
/* * The largest possible initial count is 0; this is equivalent * to 216 for binary counting and 104 for BCD counting.
*/ if (val == 0)
val = 0x10000;
ps->channels[channel].count = val;
if (channel != 0) {
ps->channels[channel].count_load_time = ktime_get(); return;
}
/* Two types of timer
* mode 1 is one shot, mode 2 is period, otherwise del timer */ switch (ps->channels[0].mode) { case 0: case 1: /* FIXME: enhance mode 4 precision */ case 4:
create_pit_timer(pit, val, 0); break; case 2: case 3:
create_pit_timer(pit, val, 1); break; default:
destroy_pit_timer(pit);
}
}
staticvoid kvm_pit_load_count(struct kvm_pit *pit, int channel, u32 val, int hpet_legacy_start)
{
u8 saved_mode;
int kvm_vm_ioctl_set_pit(struct kvm *kvm, struct kvm_pit_state *ps)
{ int i; struct kvm_pit *pit = kvm->arch.vpit;
mutex_lock(&pit->pit_state.lock);
memcpy(&pit->pit_state.channels, ps, sizeof(*ps)); for (i = 0; i < 3; i++)
kvm_pit_load_count(pit, i, ps->channels[i].count, 0);
mutex_unlock(&pit->pit_state.lock); return 0;
}
/* pit->pit_state.lock was overloaded to prevent userspace from getting * an inconsistent state after running multiple KVM_REINJECT_CONTROL * ioctls in parallel. Use a separate lock if that ioctl isn't rare.
*/
mutex_lock(&pit->pit_state.lock);
kvm_pit_set_reinject(pit, control->pit_reinject);
mutex_unlock(&pit->pit_state.lock);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.