int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu)
{
- struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ struct kvm_lapic *apic = vcpu->apic;
int highest_irr;
if (!apic)
static u32 apic_get_tmcct(struct kvm_lapic *apic)
{
- u32 counter_passed;
- ktime_t passed, now = apic->timer.dev.base->get_time();
- u32 tmcct = apic_get_reg(apic, APIC_TMICT);
+ u64 counter_passed;
+ ktime_t passed, now;
+ u32 tmcct;
ASSERT(apic != NULL);
+ now = apic->timer.dev.base->get_time();
+ tmcct = apic_get_reg(apic, APIC_TMICT);
+
+ /* if initial count is 0, current count should also be 0 */
+ if (tmcct == 0)
+ return 0;
+
if (unlikely(ktime_to_ns(now) <=
ktime_to_ns(apic->timer.last_update))) {
/* Wrap around */
counter_passed = div64_64(ktime_to_ns(passed),
(APIC_BUS_CYCLE_NS * apic->timer.divide_count));
- tmcct -= counter_passed;
- if (tmcct <= 0) {
- if (unlikely(!apic_lvtt_period(apic)))
+ if (counter_passed > tmcct) {
+ if (unlikely(!apic_lvtt_period(apic))) {
+ /* one-shot timers stick at 0 until reset */
tmcct = 0;
- else
- do {
- tmcct += apic_get_reg(apic, APIC_TMICT);
- } while (tmcct <= 0);
+ } else {
+ /*
+ * periodic timers reset to APIC_TMICT when they
+ * hit 0. The while loop simulates this happening N
+ * times. (counter_passed %= tmcct) would also work,
+ * but might be slower or not work on 32-bit??
+ */
+ while (counter_passed > tmcct)
+ counter_passed -= tmcct;
+ tmcct -= counter_passed;
+ }
+ } else {
+ tmcct -= counter_passed;
}
return tmcct;
return ret;
}
-void kvm_free_apic(struct kvm_lapic *apic)
+void kvm_free_lapic(struct kvm_vcpu *vcpu)
{
- if (!apic)
+ if (!vcpu->apic)
return;
- hrtimer_cancel(&apic->timer.dev);
+ hrtimer_cancel(&vcpu->apic->timer.dev);
- if (apic->regs_page) {
- __free_page(apic->regs_page);
- apic->regs_page = 0;
- }
+ if (vcpu->apic->regs_page)
+ __free_page(vcpu->apic->regs_page);
- kfree(apic);
+ kfree(vcpu->apic);
}
/*
void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long cr8)
{
- struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ struct kvm_lapic *apic = vcpu->apic;
if (!apic)
return;
u64 kvm_lapic_get_cr8(struct kvm_vcpu *vcpu)
{
- struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ struct kvm_lapic *apic = vcpu->apic;
u64 tpr;
if (!apic)
void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value)
{
- struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ struct kvm_lapic *apic = vcpu->apic;
if (!apic) {
value |= MSR_IA32_APICBASE_BSP;
apic_set_reg(apic, APIC_ISR + 0x10 * i, 0);
apic_set_reg(apic, APIC_TMR + 0x10 * i, 0);
}
- apic->timer.divide_count = 0;
+ update_divide_count(apic);
atomic_set(&apic->timer.pending, 0);
if (vcpu->vcpu_id == 0)
vcpu->apic_base |= MSR_IA32_APICBASE_BSP;
int kvm_lapic_enabled(struct kvm_vcpu *vcpu)
{
- struct kvm_lapic *apic = (struct kvm_lapic *)vcpu->apic;
+ struct kvm_lapic *apic = vcpu->apic;
int ret = 0;
if (!apic)
wait_queue_head_t *q = &apic->vcpu->wq;
atomic_inc(&apic->timer.pending);
- if (waitqueue_active(q))
- {
+ if (waitqueue_active(q)) {
apic->vcpu->mp_state = VCPU_MP_STATE_RUNNABLE;
wake_up_interruptible(q);
}
if (apic->regs_page == NULL) {
printk(KERN_ERR "malloc apic regs error for vcpu %x\n",
vcpu->vcpu_id);
- goto nomem;
+ goto nomem_free_apic;
}
apic->regs = page_address(apic->regs_page);
memset(apic->regs, 0, PAGE_SIZE);
apic->dev.private = apic;
return 0;
+nomem_free_apic:
+ kfree(apic);
nomem:
- kvm_free_apic(apic);
return -ENOMEM;
}
EXPORT_SYMBOL_GPL(kvm_create_lapic);