RE: [PATCH v5 2/3] x86, apicv: add virtual interrupt delivery support

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <kevin.tian@xxxxxxxxx>
>>>> Signed-off-by: Yang Zhang <yang.z.zhang@xxxxxxxxx>
>>>> ---
>>>>  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 majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux