include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / arch / x86 / kvm / lapic.c
index 683345a..1eb7a4a 100644 (file)
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/math64.h>
+#include <linux/slab.h>
 #include <asm/processor.h>
 #include <asm/msr.h>
 #include <asm/page.h>
 #include <asm/current.h>
 #include <asm/apicdef.h>
 #include <asm/atomic.h>
-#include <asm/apicdef.h>
 #include "kvm_cache_regs.h"
 #include "irq.h"
 #include "trace.h"
@@ -374,7 +374,15 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                if (unlikely(!apic_enabled(apic)))
                        break;
 
+               if (trig_mode) {
+                       apic_debug("level trig mode for vector %d", vector);
+                       apic_set_vector(vector, apic->regs + APIC_TMR);
+               } else
+                       apic_clear_vector(vector, apic->regs + APIC_TMR);
+
                result = !apic_test_and_set_irr(vector, apic);
+               trace_kvm_apic_accept_irq(vcpu->vcpu_id, delivery_mode,
+                                         trig_mode, vector, !result);
                if (!result) {
                        if (trig_mode)
                                apic_debug("level trig mode repeatedly for "
@@ -382,11 +390,6 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,
                        break;
                }
 
-               if (trig_mode) {
-                       apic_debug("level trig mode for vector %d", vector);
-                       apic_set_vector(vector, apic->regs + APIC_TMR);
-               } else
-                       apic_clear_vector(vector, apic->regs + APIC_TMR);
                kvm_vcpu_kick(vcpu);
                break;
 
@@ -469,11 +472,8 @@ static void apic_set_eoi(struct kvm_lapic *apic)
                trigger_mode = IOAPIC_LEVEL_TRIG;
        else
                trigger_mode = IOAPIC_EDGE_TRIG;
-       if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI)) {
-               mutex_lock(&apic->vcpu->kvm->irq_lock);
+       if (!(apic_get_reg(apic, APIC_SPIV) & APIC_SPIV_DIRECTED_EOI))
                kvm_ioapic_update_eoi(apic->vcpu->kvm, vector, trigger_mode);
-               mutex_unlock(&apic->vcpu->kvm->irq_lock);
-       }
 }
 
 static void apic_send_ipi(struct kvm_lapic *apic)
@@ -493,6 +493,8 @@ static void apic_send_ipi(struct kvm_lapic *apic)
        else
                irq.dest_id = GET_APIC_DEST_FIELD(icr_high);
 
+       trace_kvm_apic_ipi(icr_low, irq.dest_id);
+
        apic_debug("icr_high 0x%x, icr_low 0x%x, "
                   "short_hand 0x%x, dest 0x%x, trig_mode 0x%x, level 0x%x, "
                   "dest_mode 0x%x, delivery_mode 0x%x, vector 0x%x\n",
@@ -500,9 +502,7 @@ static void apic_send_ipi(struct kvm_lapic *apic)
                   irq.trig_mode, irq.level, irq.dest_mode, irq.delivery_mode,
                   irq.vector);
 
-       mutex_lock(&apic->vcpu->kvm->irq_lock);
        kvm_irq_delivery_to_apic(apic->vcpu->kvm, apic, &irq);
-       mutex_unlock(&apic->vcpu->kvm->irq_lock);
 }
 
 static u32 apic_get_tmcct(struct kvm_lapic *apic)
@@ -517,7 +517,7 @@ static u32 apic_get_tmcct(struct kvm_lapic *apic)
        if (apic_get_reg(apic, APIC_TMICT) == 0)
                return 0;
 
-       remaining = hrtimer_expires_remaining(&apic->lapic_timer.timer);
+       remaining = hrtimer_get_remaining(&apic->lapic_timer.timer);
        if (ktime_to_ns(remaining) < 0)
                remaining = ktime_set(0, 0);
 
@@ -593,14 +593,14 @@ static int apic_reg_read(struct kvm_lapic *apic, u32 offset, int len,
        static const u64 rmask = 0x43ff01ffffffe70cULL;
 
        if ((alignment + len) > 4) {
-               printk(KERN_ERR "KVM_APIC_READ: alignment error %x %d\n",
-                               offset, len);
+               apic_debug("KVM_APIC_READ: alignment error %x %d\n",
+                          offset, len);
                return 1;
        }
 
        if (offset > 0x3f0 || !(rmask & (1ULL << (offset >> 4)))) {
-               printk(KERN_ERR "KVM_APIC_READ: read reserved register %x\n",
-                               offset);
+               apic_debug("KVM_APIC_READ: read reserved register %x\n",
+                          offset);
                return 1;
        }
 
@@ -660,12 +660,21 @@ 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) *
+       apic->lapic_timer.period = (u64)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)
                return;
+       /*
+        * Do not allow the guest to program periodic timers with small
+        * interval, since the hrtimers are not throttled by the host
+        * scheduler.
+        */
+       if (apic_lvtt_period(apic)) {
+               if (apic->lapic_timer.period < NSEC_PER_MSEC/2)
+                       apic->lapic_timer.period = NSEC_PER_MSEC/2;
+       }
 
        hrtimer_start(&apic->lapic_timer.timer,
                      ktime_add_ns(now, apic->lapic_timer.period),
@@ -834,7 +843,7 @@ static int apic_mmio_write(struct kvm_io_device *this,
        if (len != 4 || (offset & 0xf)) {
                /* Don't shout loud, $infamous_os would cause only noise. */
                apic_debug("apic write: bad size=%d %lx\n", len, (long)address);
-               return;
+               return 0;
        }
 
        val = *(u32*)data;
@@ -1143,6 +1152,7 @@ void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu)
        hrtimer_cancel(&apic->lapic_timer.timer);
        update_divide_count(apic);
        start_apic_timer(apic);
+       apic->irr_pending = true;
 }
 
 void __kvm_migrate_apic_timer(struct kvm_vcpu *vcpu)
@@ -1237,3 +1247,34 @@ int kvm_x2apic_msr_read(struct kvm_vcpu *vcpu, u32 msr, u64 *data)
 
        return 0;
 }
+
+int kvm_hv_vapic_msr_write(struct kvm_vcpu *vcpu, u32 reg, u64 data)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+
+       if (!irqchip_in_kernel(vcpu->kvm))
+               return 1;
+
+       /* if this is ICR write vector before command */
+       if (reg == APIC_ICR)
+               apic_reg_write(apic, APIC_ICR2, (u32)(data >> 32));
+       return apic_reg_write(apic, reg, (u32)data);
+}
+
+int kvm_hv_vapic_msr_read(struct kvm_vcpu *vcpu, u32 reg, u64 *data)
+{
+       struct kvm_lapic *apic = vcpu->arch.apic;
+       u32 low, high = 0;
+
+       if (!irqchip_in_kernel(vcpu->kvm))
+               return 1;
+
+       if (apic_reg_read(apic, reg, 4, &low))
+               return 1;
+       if (reg == APIC_ICR)
+               apic_reg_read(apic, APIC_ICR2, 4, &high);
+
+       *data = (((u64)high) << 32) | low;
+
+       return 0;
+}