This patch is the main point of the series.  In order for
kdump to properly work inside a KVM guest, we need to make
sure that all VCPUs in virtual wire APIC mode get kicked
to try and pick up the timer interrupts.  To do this,
we iterate over the CPUs and deliver interrupts to the
proper VCPUs.

I don't love the concept of doing kvm_irq_kick_vcpus() from
within pit_timer_fn().  A PIT is not connected to a CPU at all,
only to a PIC or APIC.  However, if a CPU enters idle, this is
the only way to wake it up to check for the interrupt.

Signed-off-by: Chris Lalancette <clala...@redhat.com>
---
:100644 100644 d5c08fa... fe08823... M  arch/x86/kvm/i8254.c
:100644 100644 411110f... 5b699c1... M  arch/x86/kvm/lapic.c
:100644 100644 40010b0... 9c4e52b... M  arch/x86/kvm/lapic.h
:100644 100644 053e49f... 975b0d6... M  include/linux/kvm_host.h
:100644 100644 cd6f92b... 717d265... M  virt/kvm/ioapic.c
:100644 100644 0d454d3... d24ac91... M  virt/kvm/irq_comm.c
 arch/x86/kvm/i8254.c     |    3 +--
 arch/x86/kvm/lapic.c     |   12 ++++++++++++
 arch/x86/kvm/lapic.h     |    1 +
 include/linux/kvm_host.h |    2 ++
 virt/kvm/ioapic.c        |    9 ---------
 virt/kvm/irq_comm.c      |   12 ++++++++++++
 6 files changed, 28 insertions(+), 11 deletions(-)

diff --git a/arch/x86/kvm/i8254.c b/arch/x86/kvm/i8254.c
index d5c08fa..fe08823 100644
--- a/arch/x86/kvm/i8254.c
+++ b/arch/x86/kvm/i8254.c
@@ -299,8 +299,7 @@ static enum hrtimer_restart pit_timer_fn(struct hrtimer 
*data)
        if (ktimer->reinject || !atomic_read(&ktimer->pending))
                atomic_inc(&ktimer->pending);
 
-       if (waitqueue_active(&ktimer->kvm->bsp_vcpu->wq))
-               wake_up_interruptible(&ktimer->kvm->bsp_vcpu->wq);
+       kvm_irq_kick_vcpus(ktimer->kvm);
 
        if (ktimer->t_ops->is_periodic(ktimer)) {
                hrtimer_add_expires_ns(&ktimer->timer, ktimer->period);
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 411110f..5b699c1 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1031,6 +1031,18 @@ void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu)
                kvm_apic_local_deliver(apic, APIC_LVT0);
 }
 
+int kvm_apic_in_virtual_wire_mode(struct kvm_vcpu *vcpu)
+{
+       if (kvm_lapic_enabled(vcpu)) {
+               u32 lvt0 = apic_get_reg(vcpu->arch.apic, APIC_LVT0);
+               if ((lvt0 & APIC_LVT_MASKED) == 0 &&
+                   GET_APIC_DELIVERY_MODE(lvt0) == APIC_MODE_EXTINT)
+                       return 1;
+       }
+
+       return 0;
+}
+
 static struct kvm_timer_ops lapic_timer_ops = {
        .is_periodic = lapic_is_periodic,
 };
diff --git a/arch/x86/kvm/lapic.h b/arch/x86/kvm/lapic.h
index 40010b0..9c4e52b 100644
--- a/arch/x86/kvm/lapic.h
+++ b/arch/x86/kvm/lapic.h
@@ -30,6 +30,7 @@ void kvm_lapic_set_tpr(struct kvm_vcpu *vcpu, unsigned long 
cr8);
 void kvm_lapic_set_base(struct kvm_vcpu *vcpu, u64 value);
 u64 kvm_lapic_get_base(struct kvm_vcpu *vcpu);
 void kvm_apic_set_version(struct kvm_vcpu *vcpu);
+int kvm_apic_in_virtual_wire_mode(struct kvm_vcpu *vcpu);
 
 int kvm_apic_match_physical_addr(struct kvm_lapic *apic, u16 dest);
 int kvm_apic_match_logical_addr(struct kvm_lapic *apic, u8 mda);
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 053e49f..975b0d6 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -542,6 +542,8 @@ int kvm_set_irq_routing(struct kvm *kvm,
                        unsigned flags);
 void kvm_free_irq_routing(struct kvm *kvm);
 
+void kvm_irq_kick_vcpus(struct kvm *kvm);
+
 #else
 
 static inline void kvm_free_irq_routing(struct kvm *kvm) {}
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index cd6f92b..717d265 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -163,15 +163,6 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int 
irq)
        irqe.level = 1;
        irqe.shorthand = 0;
 
-#ifdef CONFIG_X86
-       /* Always deliver PIT interrupt to vcpu 0 */
-       if (irq == 0) {
-               irqe.dest_mode = 0; /* Physical mode. */
-               /* need to read apic_id from apic regiest since
-                * it can be rewritten */
-               irqe.dest_id = ioapic->kvm->bsp_vcpu->vcpu_id;
-       }
-#endif
        return kvm_irq_delivery_to_apic(ioapic->kvm, NULL, &irqe);
 }
 
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index 0d454d3..d24ac91 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -293,6 +293,18 @@ void kvm_free_irq_routing(struct kvm *kvm)
        kfree(kvm->irq_routing);
 }
 
+void kvm_irq_kick_vcpus(struct kvm *kvm)
+{
+       int i;
+       struct kvm_vcpu *vcpu;
+
+       kvm_for_each_vcpu(i, vcpu, kvm) {
+               if (kvm_apic_in_virtual_wire_mode(vcpu))
+                       if (waitqueue_active(&vcpu->wq))
+                               wake_up_interruptible(&vcpu->wq);
+       }
+}
+
 static int setup_routing_entry(struct kvm_irq_routing_table *rt,
                               struct kvm_kernel_irq_routing_entry *e,
                               const struct kvm_irq_routing_entry *ue)
-- 
1.6.0.6

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to