Gleb Natapov wrote on 2012-12-11:
> On Tue, Dec 11, 2012 at 12:05:39PM +0000, Zhang, Yang Z wrote:
>> Gleb Natapov wrote on 2012-12-11:
>>> Looks very good overall. Are you testing this with vid disabled with
>>> Linux/Windows guests? Small comments below.
>> Yes. I tested rhel6u3, rhel5u4, winxp and win7. All of them work well
>> with and without vid enabled.
>>
>>> On Mon, Dec 10, 2012 at 03:20:39PM +0800, Yang Zhang wrote:
>>>> Virtual interrupt delivery avoids KVM to inject vAPIC interrupts
>>>> manually, which is fully taken care of by the hardware. This needs
>>>> some special awareness into existing interrupr injection path:
>>>>
>>>> - for pending interrupt, instead of direct injection, we may need
>>>> update architecture specific indicators before resuming to guest. -
>>>> A pending interrupt, which is masked by ISR, should be also
>>>> considered in above update action, since hardware will decide when
>>>> to inject it at right time. Current has_interrupt and get_interrupt
>>>> only returns a valid vector from injection p.o.v.
>>>> Signed-off-by: Kevin Tian <[email protected]>
>>>> Signed-off-by: Yang Zhang <[email protected]>
>>>> ---
>>>> arch/ia64/kvm/lapic.h | 6 ++
>>>> arch/x86/include/asm/kvm_host.h | 5 ++
> arch/x86/include/asm/vmx.h
>>>> | 11 ++++ arch/x86/kvm/irq.c | 76
>>>> ++++++++++++++++++++++------ arch/x86/kvm/lapic.c | 99
>>>> +++++++++++++++++++++++++++++++++--- arch/x86/kvm/lapic.h
> |
>>>> 9 +++ arch/x86/kvm/svm.c | 25 +++++++++
>>>> arch/x86/kvm/vmx.c | 104
>>>> +++++++++++++++++++++++++++++++++++++-- arch/x86/kvm/x86.c
>>>> | 18 ++++--- include/linux/kvm_host.h | 2 +
>>>> virt/kvm/ioapic.c | 35 +++++++++++++
> virt/kvm/ioapic.h
>>>> | 1 + virt/kvm/irq_comm.c | 18
> +++++++
>>>> 13 files changed, 372 insertions(+), 37 deletions(-)
>>>> diff --git a/arch/ia64/kvm/lapic.h b/arch/ia64/kvm/lapic.h
>>>> index c5f92a9..cb59eb4 100644
>>>> --- a/arch/ia64/kvm/lapic.h
>>>> +++ b/arch/ia64/kvm/lapic.h
>>>> @@ -27,4 +27,10 @@ int kvm_apic_set_irq(struct kvm_vcpu *vcpu, struct
>>> kvm_lapic_irq *irq);
>>>> #define kvm_apic_present(x) (true)
>>>> #define kvm_lapic_enabled(x) (true)
>>>> +static inline void kvm_update_eoi_exitmap(struct kvm *kvm,
>>>> + struct kvm_lapic_irq *irq)
>>>> +{
>>>> + /* IA64 has no apicv supporting, do nothing here */
>>>> +}
>>>> +
>>>> #endif
>>>> diff --git a/arch/x86/include/asm/kvm_host.h
>>>> b/arch/x86/include/asm/kvm_host.h index dc87b65..d797ade 100644 ---
>>>> a/arch/x86/include/asm/kvm_host.h +++
>>>> b/arch/x86/include/asm/kvm_host.h @@ -697,6 +697,10 @@ struct
>>>> kvm_x86_ops {
>>>> void (*enable_nmi_window)(struct kvm_vcpu *vcpu);
>>>> void (*enable_irq_window)(struct kvm_vcpu *vcpu);
>>>> void (*update_cr8_intercept)(struct kvm_vcpu *vcpu, int tpr, int irr);
>>>> + int (*has_virtual_interrupt_delivery)(struct kvm_vcpu *vcpu);
>>>> + void (*update_irq)(struct kvm_vcpu *vcpu, int max_irr);
>>> Lets call it update_apic_irq since this is what is does.
>> Ok.
>>
>>>> +/*
>>>> * Read pending interrupt vector and intack.
>>>> */
>>>> int kvm_cpu_get_interrupt(struct kvm_vcpu *v) { - struct kvm_pic *s;
>>>> int vector;
>>>>
>>>> if (!irqchip_in_kernel(v->kvm))
>>>> return v->arch.interrupt.nr;
>>>> - vector = kvm_get_apic_interrupt(v); /* APIC */
>>>> - if (vector == -1) {
>>>> - if (kvm_apic_accept_pic_intr(v)) {
>>>> - s = pic_irqchip(v->kvm);
>>>> - s->output = 0; /* PIC */
>>>> - vector = kvm_pic_read_irq(v->kvm);
>>>> - }
>>>> + if (kvm_apic_vid_enabled(v))
>>>> + vector = kvm_cpu_get_extint(v); /* non-APIC */
>>>> + else {
>>>> + vector = kvm_get_apic_interrupt(v); /* APIC */
>>>> + if (vector == -1)
>>>> + vector = kvm_cpu_get_extint(v); /* non-APIC */
>>>> }
>>> I've send the patch to fix ExtINT handling. Can you review it and rebase on
>>> top of it?
>> Sorry. I missed it.
> http://permalink.gmane.org/gmane.comp.emulators.kvm.devel/102159.
>
>>> From performance point, I thought this is not friendly. As we known, Extint
> interrupt is used rarely(it may only exist when in virtual wire mode).
> When guest boot up, it is in apic mode. So most of time, interrupts are
> went to apic not pic. And it seems check extint first is unnecessary.
> From my point, if there is no correctness issue, virtualization isn't
> force to follow the hardware's behavior. We try to follow hardware
> behavior as close as possible and when we fail to do so we often regret
> it. Furthermore we do not want to have different behaviour with and
> without vid. kvm_cpu_has_interrupt() can continue checking apic before
> ExtINT since this will not change function return value, but without
> evidence of performance degradation I prefer kvm_cpu_has_interrupt() and
> kvm_cpu_get_interrupt() to have similar logic. kvm_cpu_has_interrupt()
> is called relatively rare (only when KVM_REQ_EVENT is set) and the check
> is very light and can be optimized further.
Ok. We can optimized it further if it really cause problem.
I will rebase the patch based on this.
>>
>>>> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
>>>> index 3bdaf29..060f36b 100644
>>>> --- a/arch/x86/kvm/x86.c
>>>> +++ b/arch/x86/kvm/x86.c
>>>> @@ -5534,12 +5534,10 @@ static void inject_pending_event(struct
> kvm_vcpu
>>> *vcpu)
>>>> vcpu->arch.nmi_injected = true;
>>>> kvm_x86_ops->set_nmi(vcpu);
>>>> }
>>>> - } else if (kvm_cpu_has_interrupt(vcpu)) { - if
>>>> (kvm_x86_ops->interrupt_allowed(vcpu)) {
>>>> - kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu),
>>>> -
>>>> false); - kvm_x86_ops->set_irq(vcpu); - } +
>>>> } else if
>>>> (kvm_cpu_has_injectable_intr(vcpu) &&
>>>> + kvm_x86_ops->interrupt_allowed(vcpu)) {
>>>> + kvm_queue_interrupt(vcpu, kvm_cpu_get_interrupt(vcpu), false);
>>>> + kvm_x86_ops->set_irq(vcpu);
>>> Please do not change indentation unnecessary. Now this block has
>>> different one from previous. Ok.
>>>
>>>> }
>>>> }
>>>> @@ -5655,6 +5653,8 @@ static int vcpu_enter_guest(struct kvm_vcpu
> *vcpu)
>>>> kvm_handle_pmu_event(vcpu);
>>>> if (kvm_check_request(KVM_REQ_PMI, vcpu))
>>>> kvm_deliver_pmi(vcpu);
>>>> + if (kvm_check_request(KVM_REQ_EOIBITMAP, vcpu))
>>>> + kvm_x86_ops->load_eoi_exitmap(vcpu);
>>>> }
>>>>
>>>> if (kvm_check_request(KVM_REQ_EVENT, vcpu) || req_int_win) {
>>>> @@ -5663,10 +5663,14 @@ static int vcpu_enter_guest(struct kvm_vcpu
>>> *vcpu)
>>>> /* enable NMI/IRQ window open exits if needed */
>>>> if (vcpu->arch.nmi_pending)
>>>> kvm_x86_ops->enable_nmi_window(vcpu);
>>>> - else if (kvm_cpu_has_interrupt(vcpu) || req_int_win)
>>>> + else if (kvm_cpu_has_injectable_intr(vcpu) || req_int_win)
>>>> kvm_x86_ops->enable_irq_window(vcpu);
>>>>
>>>> if (kvm_lapic_enabled(vcpu)) {
>>>> + /* update archtecture specific hints for APIC
>>>> + * virtual interrupt delivery */
>>>> + kvm_x86_ops->update_irq(vcpu,
>>>> + kvm_lapic_find_highest_irr(vcpu));
>>> Hmm, OK so now we scan IRR even if vid is not enabled. Yeah, I know I
>>> suggested it :). So lets do it similarly to cr8_update callback. If vid is
>>> disabled set kvm_x86_ops->update_irq to NULL. Here do
>>> if (kvm_x86_ops->update_apic_irq)
>>> kvm_x86_ops->update_apic_irq(vcpu,
> kvm_lapic_find_highest_irr(vcpu));
>>> Or write small helper function like update_cr8_intercept() below.
>> Ok.
>>
>>>> diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
>>>> index cfb7e4d..e214ea4 100644
>>>> --- a/virt/kvm/ioapic.c
>>>> +++ b/virt/kvm/ioapic.c
>>>> @@ -115,6 +115,40 @@ static void update_handled_vectors(struct
> kvm_ioapic
>>> *ioapic)
>>>> smp_wmb();
>>>> }
>>>> +static void ioapic_update_eoi_exitmap_one(struct kvm_ioapic *ioapic,
>>>> int pin) +{ + union kvm_ioapic_redirect_entry *e; + + e =
>>>> &ioapic->redirtbl[pin]; + + /* PIT is a special case: which is edge
>>>> trig but have EOI hook. + * Always set the eoi exit bitmap for PIT
>>>> interrupt*/
>>> Drop the comment.
>>>
>>>> + if (!e->fields.mask &&
>>> Drop this from here. You have it in the caller now.
>> Ok.
>>>> diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
>>>> index 2eb58af..93ecd2a 100644
>>>> --- a/virt/kvm/irq_comm.c
>>>> +++ b/virt/kvm/irq_comm.c
>>>> @@ -178,6 +178,24 @@ int kvm_set_irq(struct kvm *kvm, int irq_source_id,
>>> u32 irq, int level)
>>>> return ret;
>>>> }
>>>> +bool kvm_irq_has_notifier(struct kvm *kvm, unsigned irqchip,
>>>> unsigned pin) +{ + struct kvm_irq_ack_notifier *kian; + struct
>>>> hlist_node *n; + int gsi; + + rcu_read_lock(); + gsi =
>>>> rcu_dereference(kvm->irq_routing)->chip[irqchip][pin]; + if (gsi !=
>>>> -1) + hlist_for_each_entry_rcu(kian, n,
>>>> &kvm->irq_ack_notifier_list,
>>>> + link) + if
>>>> (kian->gsi == gsi) + return true;
>>>> + rcu_read_unlock(); + + return false; +} +
>>> Shouldn't you call ioapic_update_eoi_exitmap() in
>>> kvm_(un)register_irq_ack_notifier() too?
>> Right. Will add it in next patch.
>>
>> Best regards,
>> Yang
>>
>
> --
> Gleb.
Best regards,
Yang
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html