This moves the tpr shadow processing into the local apic code from the vmx interrupt injection path. This will allow decoupling the irq injection path from normal execution (which needs to update the tpr threshold even when no irq is being injected).
Signed-off-by: Avi Kivity <[EMAIL PROTECTED]> --- drivers/kvm/irq.c | 6 ++++-- drivers/kvm/irq.h | 8 +++++--- drivers/kvm/kvm_main.c | 3 ++- drivers/kvm/lapic.c | 17 ++++++++++++----- drivers/kvm/svm.c | 3 ++- drivers/kvm/vmx.c | 19 ++++++------------- 6 files changed, 31 insertions(+), 25 deletions(-) diff --git a/drivers/kvm/irq.c b/drivers/kvm/irq.c index 66d1a91..8a95eef 100644 --- a/drivers/kvm/irq.c +++ b/drivers/kvm/irq.c @@ -28,9 +28,11 @@ /* * Read pending interrupt vector and intack. */ -bool kvm_cpu_get_interrupt(struct kvm_vcpu *v, struct kvm_pending_irq *irq) +bool kvm_cpu_get_interrupt(struct kvm_vcpu *v, struct kvm_pending_irq *irq, + unsigned *tpr_threshold) { - if (kvm_get_apic_interrupt(v, irq)) + *tpr_threshold = 0; + if (kvm_get_apic_interrupt(v, irq, tpr_threshold)) return true; if (kvm_apic_accept_pic_intr(v)) return kvm_pic_read_irq(pic_irqchip(v->kvm), irq); diff --git a/drivers/kvm/irq.h b/drivers/kvm/irq.h index 49af30b..c12734d 100644 --- a/drivers/kvm/irq.h +++ b/drivers/kvm/irq.h @@ -63,7 +63,8 @@ struct kvm_pic { struct kvm_pic *kvm_create_pic(struct kvm *kvm); void kvm_pic_set_irq(void *opaque, int irq, int level); bool kvm_pic_read_irq(struct kvm_pic *s, struct kvm_pending_irq *irq); -bool kvm_cpu_get_interrupt(struct kvm_vcpu *v, struct kvm_pending_irq *irq); +bool kvm_cpu_get_interrupt(struct kvm_vcpu *v, struct kvm_pending_irq *irq, + unsigned *tpr_threshold); void kvm_pic_update_irq(struct kvm_pic *s); #define IOAPIC_NUM_PINS KVM_IOAPIC_NUM_PINS @@ -147,9 +148,10 @@ do { \ #endif void kvm_vcpu_kick(struct kvm_vcpu *vcpu); -int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); +int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu, unsigned *tpr_threshold); int kvm_apic_accept_pic_intr(struct kvm_vcpu *vcpu); -bool kvm_get_apic_interrupt(struct kvm_vcpu *vcpu, struct kvm_pending_irq *irq); +bool kvm_get_apic_interrupt(struct kvm_vcpu *vcpu, struct kvm_pending_irq *irq, + unsigned *tpr_threshold); int kvm_create_lapic(struct kvm_vcpu *vcpu); void kvm_lapic_reset(struct kvm_vcpu *vcpu); void kvm_pic_reset(struct kvm_kpic_state *s); diff --git a/drivers/kvm/kvm_main.c b/drivers/kvm/kvm_main.c index 41658d7..7cc4508 100644 --- a/drivers/kvm/kvm_main.c +++ b/drivers/kvm/kvm_main.c @@ -638,13 +638,14 @@ void kvm_vcpu_block(struct kvm_vcpu *vcpu) { DECLARE_WAITQUEUE(wait, current); struct kvm_pending_irq irq; + unsigned tpr_threshold; add_wait_queue(&vcpu->wq, &wait); /* * We will block until either an interrupt or a signal wakes us up */ - while (!kvm_cpu_get_interrupt(vcpu, &irq) + while (!kvm_cpu_get_interrupt(vcpu, &irq, &tpr_threshold) && !signal_pending(current) && vcpu->mp_state != VCPU_MP_STATE_RUNNABLE && vcpu->mp_state != VCPU_MP_STATE_SIPI_RECEIVED) { diff --git a/drivers/kvm/lapic.c b/drivers/kvm/lapic.c index 804a177..f2168d4 100644 --- a/drivers/kvm/lapic.c +++ b/drivers/kvm/lapic.c @@ -992,19 +992,25 @@ nomem: } EXPORT_SYMBOL_GPL(kvm_create_lapic); -int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) +int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu, unsigned *tpr_threshold) { struct kvm_lapic *apic = vcpu->apic; int highest_irr; + unsigned tpr; if (!apic || !apic_enabled(apic)) return -1; apic_update_ppr(apic); highest_irr = apic_find_highest_irr(apic); - if ((highest_irr == -1) || - ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI))) + if (highest_irr == -1) return -1; + if ((highest_irr & 0xF0) <= apic_get_reg(apic, APIC_PROCPRI)) { + tpr = apic_get_reg(apic, APIC_TASKPRI) & 0xff; + if ((highest_irr & 0xF0) < tpr) + *tpr_threshold = highest_irr & 0xF0; + return -1; + } return highest_irr; } @@ -1053,9 +1059,10 @@ static void kvm_apic_ack_interrupt(struct kvm_vcpu *vcpu, unsigned vector) apic_clear_irr(vector, apic); } -bool kvm_get_apic_interrupt(struct kvm_vcpu *vcpu, struct kvm_pending_irq *irq) +bool kvm_get_apic_interrupt(struct kvm_vcpu *vcpu, struct kvm_pending_irq *irq, + unsigned *tpr_threshold) { - int vector = kvm_apic_has_interrupt(vcpu); + int vector = kvm_apic_has_interrupt(vcpu, tpr_threshold); if (vector == -1) return false; diff --git a/drivers/kvm/svm.c b/drivers/kvm/svm.c index 155b266..10146a8 100644 --- a/drivers/kvm/svm.c +++ b/drivers/kvm/svm.c @@ -1317,6 +1317,7 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu) struct vmcb *vmcb = svm->vmcb; int intr_vector = -1; struct kvm_pending_irq irq; + unsigned tpr_threshold; if ((vmcb->control.exit_int_info & SVM_EVTINJ_VALID) && ((vmcb->control.exit_int_info & SVM_EVTINJ_TYPE_MASK) == 0)) { @@ -1330,7 +1331,7 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu) if (vmcb->control.int_ctl & V_IRQ_MASK) return; - if (!kvm_cpu_get_interrupt(vcpu, &irq)) + if (!kvm_cpu_get_interrupt(vcpu, &irq, &tpr_threshold)) return; if (!(vmcb->save.rflags & X86_EFLAGS_IF) || diff --git a/drivers/kvm/vmx.c b/drivers/kvm/vmx.c index ed14849..b788c6b 100644 --- a/drivers/kvm/vmx.c +++ b/drivers/kvm/vmx.c @@ -2218,21 +2218,12 @@ static void vmx_flush_tlb(struct kvm_vcpu *vcpu) { } -static void update_tpr_threshold(struct kvm_vcpu *vcpu) +static void update_tpr_threshold(struct kvm_vcpu *vcpu, unsigned tpr_threshold) { - int max_irr, tpr; - if (!vm_need_tpr_shadow(vcpu->kvm)) return; - if (!kvm_lapic_enabled(vcpu) || - ((max_irr = kvm_lapic_find_highest_irr(vcpu)) == -1)) { - vmcs_write32(TPR_THRESHOLD, 0); - return; - } - - tpr = (kvm_lapic_get_cr8(vcpu) & 0x0f) << 4; - vmcs_write32(TPR_THRESHOLD, (max_irr > tpr) ? tpr >> 4 : max_irr >> 4); + vmcs_write32(TPR_THRESHOLD, tpr_threshold >> 4); } static void enable_irq_window(struct kvm_vcpu *vcpu) @@ -2251,10 +2242,12 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) int has_ext_irq, interrupt_window_open; struct kvm_pending_irq irq; int vector; + unsigned tpr_threshold; + + has_ext_irq = kvm_cpu_get_interrupt(vcpu, &irq, &tpr_threshold); - update_tpr_threshold(vcpu); + update_tpr_threshold(vcpu, tpr_threshold); - has_ext_irq = kvm_cpu_get_interrupt(vcpu, &irq); intr_info_field = vmcs_read32(VM_ENTRY_INTR_INFO_FIELD); idtv_info_field = vmx->idt_vectoring_info; if (intr_info_field & INTR_INFO_VALID_MASK) { -- 1.5.3 ------------------------------------------------------------------------- SF.Net email is sponsored by: The Future of Linux Business White Paper from Novell. From the desktop to the data center, Linux is going mainstream. Let it simplify your IT future. http://altfarm.mediaplex.com/ad/ck/8857-50307-18918-4 _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel