KVM: VMX: Add Posted Interrupt supporting
v6 cover KVM: VMX: Add Posted Interrupt supporting
From: Yang Zhang <[email protected]>
The follwoing patches are adding the Posted Interrupt supporting to KVM:
The first patch enables the feature 'acknowledge interrupt on vmexit'.Since it is required by Posted interrupt, we need to enable it firstly.
And the subsequent patches are adding the posted interrupt supporting:
Posted Interrupt allows APIC interrupts to inject into guest directly without any vmexit.
- When delivering a interrupt to guest, if target vcpu is running, update Posted-interrupt requests bitmap and send a notification event to the vcpu. Then the vcpu will handle this interrupt automatically, without any software involvemnt.
- If target vcpu is not running or there already a notification event pending in the vcpu, do nothing. The interrupt will be handled by next vm entry
NOTE: We don't turn on the Posted Interrupt until the coalesced issue is solved.
Changes from v5 to v6:
* Split sync_pir_to_irr into two functions one to query whether PIR is empty and the other to perform the sync.
* Add comments to explain how vmx_sync_pir_to_irr() work.
* Rebase on top of KVM upstream.
Changes from v4 to v5:
* Add per cpu count for posted IPI handler.
* Dont' check irr when delivering interrupt. Since we can not get interrupt coalesced info with Posted Interrupt. So there is no need to check the irr. There is another patch will changed current interrupt coalesced logic. Before it, we will not turn on Posted Interrupt.
* Clear outstanding notification bit after call local_irq_disable, but before check request. As Marcelo suggested, we can ensure the IPI not lost in this way
* Remove the spinlock. Same as item 2, if not need to get coalesced info, then no need the lock.
* Rebase on top of KVM upstream.
Yang Zhang (5):
KVM: VMX: Enable acknowledge interupt on vmexit
KVM: VMX: Register a new IPI for posted interrupt
KVM: VMX: Check the posted interrupt capability
KVM: VMX: Add the algorithm of deliver posted interrupt KVM : VMX: Use posted interrupt to deliver virtual interrupt
arch/x86/include/asm/entry_arch.h | 4 + arch/x86/include/asm/hardirq.h | 3 + arch/x86/include/asm/hw_irq.h | 1 + arch/x86/include/asm/irq_vectors.h | 5 + arch/x86/include/asm/kvm_host.h | 5 + arch/x86/include/asm/vmx.h | 4 + arch/x86/kernel/entry_64.S | 5 + arch/x86/kernel/irq.c | 22 ++++ arch/x86/kernel/irqinit.c | 4 + arch/x86/kvm/irq.c | 3 +- arch/x86/kvm/lapic.c | 29 ++++- arch/x86/kvm/lapic.h | 2 + arch/x86/kvm/svm.c | 30 +++++ arch/x86/kvm/vmx.c | 223 ++++++++++++++++++++++++++++++++---- arch/x86/kvm/x86.c | 8 +- virt/kvm/kvm_main.c | 1 + 16 files changed, 320 insertions(+), 29 deletions(-)
PATCH v6 1/5 KVM: VMX: Enable acknowledge interupt on vmexit
From: Yang Zhang <[email protected]>
The "acknowledge interrupt on exit" feature controls processor behavior for external interrupt acknowledgement. When this control is set, the processor acknowledges the interrupt controller to acquire the interrupt vector on VM exit.
After enabling this feature, an interrupt which arrived when target cpu is running in vmx non-root mode will be handled by vmx handler instead of handler in idt. Currently, vmx handler only fakes an interrupt stack and jump to idt table to let real handler to handle it. Further, we will recognize the interrupt and only delivery the interrupt which not belong to current vcpu through idt table. The interrupt which belonged to current vcpu will be handled inside vmx handler. This will reduce the interrupt handle cost of KVM.
Also, interrupt enable logic is changed if this feature is turnning on:
Before this patch, hypervior call local_irq_enable() to enable it directly. Now IF bit is set on interrupt stack frame, and will be enabled on a return from interrupt handler if exterrupt interrupt exists. If no external interrupt, still call local_irq_enable() to enable it.
Refer to Intel SDM volum 3, chapter 33.2.
--- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/svm.c | 6 ++++ arch/x86/kvm/vmx.c | 58 ++++++++++++++++++++++++++++++++++++--- arch/x86/kvm/x86.c | 4 ++- 4 files changed, 64 insertions(+), 5 deletions(-)
arch/x86/include/asm/kvm_host.h +1 -0
@@ -730,6 +730,7 @@ struct kvm_x86_ops {int (*check_intercept)(struct kvm_vcpu *vcpu,struct x86_instruction_info *info,enum x86_intercept_stage stage); +void (*handle_external_intr)(struct kvm_vcpu *vcpu); };struct kvm_arch_async_pf {
arch/x86/kvm/svm.c +6 -0
@@ -4247,6 +4247,11 @@ out:return ret; } +static void svm_handle_external_intr (struct kvm_vcpu *vcpu) +{ +local_irq_enable (); +} +static struct kvm_x86_ops svm_x86_ops = { .cpu_has_kvm_support = has_svm, .disabled_by_bios = is_disabled,
@@ -4342,6 +4347,7 @@ static struct kvm_x86_ops svm_x86_ops = { .set_tdp_cr3 = set_tdp_cr3, .check_intercept = svm_check_intercept, + .handle_external_intr = svm_handle_external_intr, };static int __init svm_init (void )
arch/x86/kvm/vmx.c +54 -4
106 lines not on this page · raw message
arch/x86/kvm/x86.c +3 -1
@@ -5784,7 +5784,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) vcpu->mode =OUTSIDE_GUEST_MODE ;smp_wmb (); -local_irq_enable (); + +/* Interrupt is enabled by handle_external_intr() */ + kvm_x86_ops->handle_external_intr (vcpu); ++vcpu->stat.exits;
Signature · 1 line
1.7.1
PATCH v6 2/5 KVM: VMX: Register a new IPI for posted interrupt
In reply to Yang ZhangFrom: Yang Zhang <[email protected]>
Posted Interrupt feature requires a special IPI to deliver posted interrupt to guest. And it should has a high priority so the interrupt will not be blocked by others.
Normally, the posted interrupt will be consumed by vcpu if target vcpu is running and transparent to OS. But in some cases, the interrupt will arrive when target vcpu is scheduled out. And host will see it. So we need to register a dump handler to handle it.
--- arch/x86/include/asm/entry_arch.h | 4 ++++ arch/x86/include/asm/hardirq.h | 3 +++ arch/x86/include/asm/hw_irq.h | 1 + arch/x86/include/asm/irq_vectors.h | 5 +++++ arch/x86/kernel/entry_64.S | 5 +++++ arch/x86/kernel/irq.c | 22 ++++++++++++++++++++++ arch/x86/kernel/irqinit.c | 4 ++++ 7 files changed, 44 insertions(+), 0 deletions(-)
arch/x86/include/asm/entry_arch.h +4 -0
@@ -19,6 +19,10 @@ BUILD_INTERRUPT(reboot_interrupt,REBOOT_VECTOR) BUILD_INTERRUPT(x86_platform_ipi, X86_PLATFORM_IPI_VECTOR) +#ifdef CONFIG_HAVE_KVM +BUILD_INTERRUPT(kvm_posted_intr_ipi, POSTED_INTR_VECTOR) +#endif +/* * every pentium local APIC has two 'local interrupts', with a * soft-definable vector attached to both interrupts, one of
arch/x86/include/asm/hardirq.h +3 -0
@@ -12,6 +12,9 @@ typedef struct {unsigned int irq_spurious_count;unsigned int icr_read_retry_count;#endif +#ifdef CONFIG_HAVE_KVM +unsigned int kvm_posted_intr_ipis; +#endif unsigned int x86_platform_ipis;/* arch dependent */ unsigned int apic_perf_irqs;unsigned int apic_irq_work_irqs;
arch/x86/include/asm/hw_irq.h +1 -0
@@ -28,6 +28,7 @@/* Interrupt handlers registered during init_IRQ */ extern void apic_timer_interrupt (void );extern void x86_platform_ipi (void ); +extern void kvm_posted_intr_ipi (void );extern void error_interrupt (void );extern void irq_work_interrupt (void );
arch/x86/include/asm/irq_vectors.h +5 -0
@@ -102,6 +102,11 @@*/ #define X86_PLATFORM_IPI_VECTOR 0xf7 +/* Vector for KVM to deliver posted interrupt IPI */ +#ifdef CONFIG_HAVE_KVM +#define POSTED_INTR_VECTOR 0xf2 +#endif +/* * IRQ work vector: */
arch/x86/kernel/entry_64.S +5 -0
@@ -1177,6 +1177,11 @@ apicinterrupt LOCAL_TIMER_VECTOR \ apicinterrupt X86_PLATFORM_IPI_VECTOR \ x86_platform_ipi smp_x86_platform_ipi +#ifdef CONFIG_HAVE_KVM +apicinterrupt POSTED_INTR_VECTOR \ + kvm_posted_intr_ipi smp_kvm_posted_intr_ipi +#endif + apicinterrupt THRESHOLD_APIC_VECTOR \ threshold_interrupt smp_threshold_interrupt apicinterrupt THERMAL_APIC_VECTOR \
arch/x86/kernel/irq.c +22 -0
@@ -228,6 +228,28 @@ void smp_x86_platform_ipi(struct pt_regs *regs)set_irq_regs (old_regs); } +#ifdef CONFIG_HAVE_KVM +/* +* Handler for POSTED_INTERRUPT_VECTOR. +*/ +void smp_kvm_posted_intr_ipi (struct pt_regs *regs) +{ +struct pt_regs *old_regs =set_irq_regs (regs); + +ack_APIC_irq (); + +irq_enter (); + +exit_idle (); + +inc_irq_stat (kvm_posted_intr_ipis); + +irq_exit (); + +set_irq_regs (old_regs); +} +#endif +EXPORT_SYMBOL_GPL (vector_used_by_percpu_irq);#ifdef CONFIG_HOTPLUG_CPU
arch/x86/kernel/irqinit.c +4 -0
@@ -205,6 +205,10 @@ static void __init apic_intr_init(void)/* IPI for X86 platform specific use */ alloc_intr_gate (X86_PLATFORM_IPI_VECTOR , x86_platform_ipi); +#ifdef CONFIG_HAVE_KVM +/* IPI for KVM to deliver posted interrupt */ +alloc_intr_gate (POSTED_INTR_VECTOR , kvm_posted_intr_ipi); +#endif /* IPI vectors for APIC spurious and error interrupts */ alloc_intr_gate (SPURIOUS_APIC_VECTOR , spurious_interrupt);
Signature · 1 line
1.7.1
PATCH v6 3/5 KVM: VMX: Check the posted interrupt capability
In reply to Yang ZhangFrom: Yang Zhang <[email protected]>
Detect the posted interrupt feature. If it exists, then set it in vmcs_config.
--- arch/x86/include/asm/vmx.h | 4 ++ arch/x86/kvm/vmx.c | 87 ++++++++++++++++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 20 deletions(-)
arch/x86/include/asm/vmx.h +4 -0
@@ -158,6 +158,7 @@#define PIN_BASED_EXT_INTR_MASK 0x00000001#define PIN_BASED_NMI_EXITING 0x00000008#define PIN_BASED_VIRTUAL_NMIS 0x00000020 +#define PIN_BASED_POSTED_INTR 0x00000080#define VM_EXIT_SAVE_DEBUG_CONTROLS 0x00000002#define VM_EXIT_HOST_ADDR_SPACE_SIZE 0x00000200
@@ -180,6 +181,7 @@/* VMCS Encodings */ enum vmcs_field {VIRTUAL_PROCESSOR_ID =0x00000000 , +POSTED_INTR_NV =0x00000002 ,GUEST_ES_SELECTOR =0x00000800 ,GUEST_CS_SELECTOR =0x00000802 ,GUEST_SS_SELECTOR =0x00000804 ,
@@ -214,6 +216,8 @@ enum vmcs_field {VIRTUAL_APIC_PAGE_ADDR_HIGH =0x00002013 ,APIC_ACCESS_ADDR =0x00002014 ,APIC_ACCESS_ADDR_HIGH =0x00002015 , +POSTED_INTR_DESC_ADDR =0x00002016 , +POSTED_INTR_DESC_ADDR_HIGH =0x00002017 ,EPT_POINTER =0x0000201a ,EPT_POINTER_HIGH =0x0000201b , EOI_EXIT_BITMAP0 = 0x0000201c,
arch/x86/kvm/vmx.c +67 -20
178 lines not on this page · raw message
Signature · 1 line
1.7.1
PATCH v6 4/5 KVM: VMX: Add the algorithm of deliver posted interrupt
In reply to Yang ZhangFrom: Yang Zhang <[email protected]>
Only deliver the posted interrupt when target vcpu is running and there is no previous interrupt pending in pir.
--- arch/x86/include/asm/kvm_host.h | 4 ++ arch/x86/kvm/lapic.c | 13 +++++++ arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/svm.c | 24 ++++++++++++++ arch/x86/kvm/vmx.c | 67 +++++++++++++++++++++++++++++++++++++++ virt/kvm/kvm_main.c | 1 + 6 files changed, 110 insertions(+), 0 deletions(-)
arch/x86/include/asm/kvm_host.h +4 -0
@@ -704,6 +704,10 @@ struct kvm_x86_ops {void (*hwapic_isr_update)(struct kvm *kvm,int isr);void (*load_eoi_exitmap)(struct kvm_vcpu *vcpu,u64 *eoi_exit_bitmap);void (*set_virtual_x2apic_mode)(struct kvm_vcpu *vcpu,bool set); +bool (*deliver_posted_interrupt)(struct kvm_vcpu *vcpu,int vector); +void (*posted_intr_clear_on)(struct kvm_vcpu *vcpu); +void (*sync_pir_to_irr)(struct kvm_vcpu *vcpu); +bool (*hwapic_has_interrupt)(struct kvm_vcpu *vcpu);int (*set_tss_addr)(struct kvm *kvm,unsigned int addr);int (*get_tdp_level)(void );u64 (*get_mt_mask)(struct kvm_vcpu *vcpu,gfn_t gfn,bool is_mmio);
arch/x86/kvm/lapic.c +13 -0
@@ -357,6 +357,19 @@ static u8 count_vectors(void *bitmap)return count; } +void kvm_apic_update_irr (struct kvm_vcpu *vcpu,u32 *pir) +{ +u32 i, pir_val; +struct kvm_lapic *apic = vcpu->arch.apic; + +for (i =0 ; i <=7 ; i++) { + pir_val =xchg (&pir[i],0 ); +if (pir_val) + *((u32 *)(apic->regs +APIC_IRR + i *0x10 )) |= pir_val; + } +} +EXPORT_SYMBOL_GPL (kvm_apic_update_irr); +static inline int apic_test_and_set_irr (int vec,struct kvm_lapic *apic) { apic->irr_pending = true;
arch/x86/kvm/lapic.h +1 -0
@@ -157,5 +157,6 @@ static inline u16 apic_logical_id(struct kvm_apic_map *map, u32 ldr)void kvm_calculate_eoi_exitmap (struct kvm_vcpu *vcpu,struct kvm_lapic_irq *irq,u64 *eoi_bitmap); +void kvm_apic_update_irr (struct kvm_vcpu *vcpu,u32 *pir);#endif
arch/x86/kvm/svm.c +24 -0
@@ -3591,6 +3591,26 @@ static void svm_hwapic_isr_update(struct kvm *kvm, int isr)return ; } +static bool svm_hwapic_has_interrupt (struct kvm_vcpu *vcpu) +{ +return false; +} + +static void svm_sync_pir_to_irr (struct kvm_vcpu *vcpu) +{ +return ; +} + +static bool svm_deliver_posted_interrupt (struct kvm_vcpu *vcpu,int vector) +{ +return false; +} + +static void svm_posted_intr_clear_on (struct kvm_vcpu *vcpu) +{ +return ; +} +static int svm_nmi_allowed (struct kvm_vcpu *vcpu) {struct vcpu_svm *svm =to_svm (vcpu);
@@ -4319,6 +4339,10 @@ static struct kvm_x86_ops svm_x86_ops = { .vm_has_apicv = svm_vm_has_apicv, .load_eoi_exitmap = svm_load_eoi_exitmap, .hwapic_isr_update = svm_hwapic_isr_update, + .sync_pir_to_irr = svm_sync_pir_to_irr, + .hwapic_has_interrupt = svm_hwapic_has_interrupt, + .deliver_posted_interrupt = svm_deliver_posted_interrupt, + .posted_intr_clear_on = svm_posted_intr_clear_on, .set_tss_addr = svm_set_tss_addr, .get_tdp_level = get_npt_level,
arch/x86/kvm/vmx.c +67 -0
85 lines not on this page · raw message
virt/kvm/kvm_main.c +1 -0
@@ -1692,6 +1692,7 @@ void kvm_vcpu_kick(struct kvm_vcpu *vcpu)smp_send_reschedule (cpu); put_cpu(); } +EXPORT_SYMBOL_GPL (kvm_vcpu_kick);#endif /* !CONFIG_S390 */ void kvm_resched (struct kvm_vcpu *vcpu)
Signature · 1 line
1.7.1
PATCH v6 5/5 KVM : VMX: Use posted interrupt to deliver virtual interrupt
In reply to Yang ZhangFrom: Yang Zhang <[email protected]>
If posted interrupt is avaliable, then uses it to inject virtual interrupt to guest.
--- arch/x86/kvm/irq.c | 3 ++- arch/x86/kvm/lapic.c | 16 +++++++++++++--- arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/vmx.c | 11 +++++++++++ arch/x86/kvm/x86.c | 4 ++++ 5 files changed, 31 insertions(+), 4 deletions(-)
arch/x86/kvm/irq.c +2 -1
@@ -81,7 +81,8 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)if (kvm_cpu_has_extint (v))return 1 ; -return kvm_apic_has_interrupt (v) !=-1 ;/* LAPIC */ +return (kvm_apic_has_interrupt (v) !=-1 ) || +kvm_hwapic_has_interrupt (v); }EXPORT_SYMBOL_GPL (kvm_cpu_has_interrupt);
arch/x86/kvm/lapic.c +13 -3
@@ -713,7 +713,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, }else apic_clear_vector (vector, apic->regs +APIC_TMR ); - result = !apic_test_and_set_irr (vector, apic); + result =1 ; +if (!kvm_x86_ops->deliver_posted_interrupt (vcpu, vector)) + result = !apic_test_and_set_irr (vector, apic); +trace_kvm_apic_accept_irq (vcpu->vcpu_id, delivery_mode, trig_mode, vector, !result);if (!result) {
@@ -723,8 +726,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,break ; } -kvm_make_request (KVM_REQ_EVENT , vcpu); -kvm_vcpu_kick (vcpu); +if (!kvm_x86_ops->vm_has_apicv (vcpu->kvm)) { +kvm_make_request (KVM_REQ_EVENT , vcpu); +kvm_vcpu_kick (vcpu); + }break ;case APIC_DM_REMRD :
@@ -1604,6 +1609,11 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)return highest_irr; } +bool kvm_hwapic_has_interrupt (struct kvm_vcpu *vcpu) +{ +return kvm_x86_ops->hwapic_has_interrupt (vcpu); +} +int kvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu) {u32 lvt0 =kvm_apic_get_reg (vcpu->arch.apic,APIC_LVT0 );
arch/x86/kvm/lapic.h +1 -0
@@ -37,6 +37,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);void kvm_free_lapic (struct kvm_vcpu *vcpu);int kvm_apic_has_interrupt (struct kvm_vcpu *vcpu); +bool kvm_hwapic_has_interrupt (struct kvm_vcpu *vcpu);int kvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu);int kvm_get_apic_interrupt (struct kvm_vcpu *vcpu);void kvm_lapic_reset (struct kvm_vcpu *vcpu);
arch/x86/kvm/vmx.c +11 -0
@@ -3932,6 +3932,17 @@ static void vmx_posted_intr_clear_on(struct kvm_vcpu *vcpu)clear_bit (POSTED_INTR_ON , (unsigned long *)&vmx->pi_desc.u.control); } +/* +* Send interrupt to vcpu via posted interrupt way. +* Return false if posted interrupt is not supported and the caller will +* roll back to old way(via set vIRR). +* Return true if posted interrupt is avalialbe, the interrupt is set +* in pir(posted interrupt requests): +* 1. If target vcpu is running(non-root mode), send posted interrupt +* notification to vcpu and hardware will sync pir to vIRR atomically. +* 2. If target vcpu isn't running(root mode), kick it to pick up the +* interrupt from pir in next vmentry. +*/ static bool vmx_deliver_posted_interrupt (struct kvm_vcpu *vcpu,int vector) {struct vcpu_vmx *vmx =to_vmx (vcpu);
arch/x86/kvm/x86.c +4 -0
@@ -2679,6 +2679,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)static int kvm_vcpu_ioctl_get_lapic (struct kvm_vcpu *vcpu,struct kvm_lapic_state *s) { + kvm_x86_ops->sync_pir_to_irr (vcpu);memcpy (s->regs, vcpu->arch.apic->regs,sizeof *s);return 0 ;
@@ -5699,6 +5700,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) }if (kvm_check_request (KVM_REQ_EVENT , vcpu) || req_int_win) { + kvm_x86_ops->sync_pir_to_irr (vcpu);inject_pending_event (vcpu);/* enable NMI/IRQ window open exits if needed */
@@ -5741,6 +5743,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +if (vcpu->mode ==EXITING_GUEST_MODE || vcpu->requests ||need_resched () ||signal_pending (current)) { vcpu->mode =OUTSIDE_GUEST_MODE ;
Signature · 1 line
1.7.1
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 19 lines · Yang Zhang
From: Yang Zhang <[email protected]>
If posted interrupt is avaliable, then uses it to inject virtual interrupt to guest.
Signed-off-by Yang Zhang <[email protected]>--- arch/x86/kvm/irq.c | 3 ++- arch/x86/kvm/lapic.c | 16 +++++++++++++--- arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/vmx.c | 11 +++++++++++ arch/x86/kvm/x86.c | 4 ++++ 5 files changed, 31 insertions(+), 4 deletions(-)arch/x86/kvm/irq.c +0
-0
arch/x86/kvm/irq.c int kvm_cpu_has_interrupt(struct kvm_vcpu *v) · line 85
Quoted 6 lines
arch/x86/kvm/irq.c +2
-1@@ -81,7 +81,8 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)if (kvm_cpu_has_extint (v))return 1 ; -return kvm_apic_has_interrupt (v) !=-1 ;/* LAPIC */ +return (kvm_apic_has_interrupt (v) !=-1 ) || +kvm_hwapic_has_interrupt (v);
That's incorrect. kvm_cpu_has_interrupt() should return true only it there is IRR suitable to be injected, not just any IRR. kvm_apic_has_interrupt() should call kvm_apic_update_irr().
Quoted 20 lines
arch/x86/kvm/irq.c +0
-0}EXPORT_SYMBOL_GPL (kvm_cpu_has_interrupt);arch/x86/kvm/lapic.c +4
-1@@ -713,7 +713,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, }else apic_clear_vector (vector, apic->regs +APIC_TMR ); - result = !apic_test_and_set_irr (vector, apic); + result =1 ; +if (!kvm_x86_ops->deliver_posted_interrupt (vcpu, vector)) + result = !apic_test_and_set_irr (vector, apic); +trace_kvm_apic_accept_irq (vcpu->vcpu_id, delivery_mode, trig_mode, vector, !result);if (!result) {
arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, · line 733
Quoted 10 lines
arch/x86/kvm/lapic.c +4
-2@@ -723,8 +726,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode,break ; } -kvm_make_request (KVM_REQ_EVENT , vcpu); -kvm_vcpu_kick (vcpu); +if (!kvm_x86_ops->vm_has_apicv (vcpu->kvm)) { +kvm_make_request (KVM_REQ_EVENT , vcpu); +kvm_vcpu_kick (vcpu); + }break ;
apicv code and non apicv code are completely different. What's the point checking for apicv twice here?
Just do:
if (kvm_x86_ops->deliver_posted_interrupt)
kvm_x86_ops->deliver_posted_interrupt(vcpu, vector)
else {
result = !apic_test_and_set_irr(vector, apic);
kvm_make_request(KVM_REQ_EVENT, vcpu);
kvm_vcpu_kick(vcpu);
}And set kvm_x86_ops->deliver_posted_interrupt only if apicv is enabled.
Also rearrange patches so that APIC_TMR handling goes before posted interrupt series.
Quoted 35 lines
arch/x86/kvm/lapic.c +5
-0case APIC_DM_REMRD :@@ -1604,6 +1609,11 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu)return highest_irr; } +bool kvm_hwapic_has_interrupt (struct kvm_vcpu *vcpu) +{ +return kvm_x86_ops->hwapic_has_interrupt (vcpu); +} +int kvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu) {u32 lvt0 =kvm_apic_get_reg (vcpu->arch.apic,APIC_LVT0 );arch/x86/kvm/lapic.h +1
-0@@ -37,6 +37,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);void kvm_free_lapic (struct kvm_vcpu *vcpu);int kvm_apic_has_interrupt (struct kvm_vcpu *vcpu); +bool kvm_hwapic_has_interrupt (struct kvm_vcpu *vcpu);int kvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu);int kvm_get_apic_interrupt (struct kvm_vcpu *vcpu);void kvm_lapic_reset (struct kvm_vcpu *vcpu);arch/x86/kvm/vmx.c +1
-0@@ -3932,6 +3932,17 @@ static void vmx_posted_intr_clear_on(struct kvm_vcpu *vcpu)clear_bit (POSTED_INTR_ON , (unsigned long *)&vmx->pi_desc.u.control); } +/*
arch/x86/kvm/vmx.c static void vmx_posted_intr_clear_on(struct kvm_vcpu *vcpu) · line 3945
Quoted 10 lines
arch/x86/kvm/vmx.c +10
-0+* Send interrupt to vcpu via posted interrupt way. +* Return false if posted interrupt is not supported and the caller will +* roll back to old way(via set vIRR). +* Return true if posted interrupt is avalialbe, the interrupt is set +* in pir(posted interrupt requests): +* 1. If target vcpu is running(non-root mode), send posted interrupt +* notification to vcpu and hardware will sync pir to vIRR atomically. +* 2. If target vcpu isn't running(root mode), kick it to pick up the +* interrupt from pir in next vmentry. +*/
The comment should go into previous patch. Also I prefer to not check for posted interrupt inside the callback, but set it to NULL instead. This way we avoid calling a callback on a hot path needlessly.
Quoted 24 lines
arch/x86/kvm/vmx.c +0
-0static bool vmx_deliver_posted_interrupt (struct kvm_vcpu *vcpu,int vector) {struct vcpu_vmx *vmx =to_vmx (vcpu);arch/x86/kvm/x86.c +2
-0@@ -2679,6 +2679,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)static int kvm_vcpu_ioctl_get_lapic (struct kvm_vcpu *vcpu,struct kvm_lapic_state *s) { + kvm_x86_ops->sync_pir_to_irr (vcpu);memcpy (s->regs, vcpu->arch.apic->regs,sizeof *s);return 0 ;@@ -5699,6 +5700,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) }if (kvm_check_request (KVM_REQ_EVENT , vcpu) || req_int_win) { + kvm_x86_ops->sync_pir_to_irr (vcpu);inject_pending_event (vcpu);/* enable NMI/IRQ window open exits if needed */
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5747
Quoted 5 lines
arch/x86/kvm/x86.c +2
-0@@ -5741,6 +5743,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +
Why is this separate from pir_to_irr syncing?
Quoted 5 lines
arch/x86/kvm/x86.c +0
-0if (vcpu->mode ==EXITING_GUEST_MODE || vcpu->requests ||need_resched () ||signal_pending (current)) { vcpu->mode =OUTSIDE_GUEST_MODE ;Signature · 1 line
1.7.1
--
Gleb.
RE: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Gleb Natapov wrote on 2013-03-19:
Quoted 19 lines · Yang Zhang
Quoted 18 lines
From: Yang Zhang <[email protected]>
If posted interrupt is avaliable, then uses it to inject virtual interrupt to guest.
Signed-off-by Yang Zhang <[email protected]>--- arch/x86/kvm/irq.c | 3 ++- arch/x86/kvm/lapic.c | 16 +++++++++++++--- arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/vmx.c | 11 +++++++++++ arch/x86/kvm/x86.c | 4 ++++ 5 files changed, 31 insertions(+), 4 deletions(-)arch/x86/kvm/irq.c +0
-0@@ -81,7 +81,8 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)
Quoted 8 lines
arch/x86/kvm/irq.c int kvm_cpu_has_interrupt(struct kvm_vcpu *v) · line 85
Quoted 5 lines
arch/x86/kvm/irq.c +2
-1if (kvm_cpu_has_extint (v))return 1 ; -return kvm_apic_has_interrupt (v) !=-1 ;/* LAPIC */ +return (kvm_apic_has_interrupt (v) !=-1 ) || +kvm_hwapic_has_interrupt (v);That's incorrect.
kvm_cpu_has_interrupt()should return true only it there is IRR suitable to be injected, not just any IRR.kvm_apic_has_interrupt()should callkvm_apic_update_irr().
You are right.
Quoted 41 lines
arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int
Quoted 7 lines
arch/x86/kvm/irq.c +0
-0}EXPORT_SYMBOL_GPL (kvm_cpu_has_interrupt);arch/x86/kvm/lapic.c +0
-0@@ -713,7 +713,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int
Quoted 11 lines
arch/x86/kvm/lapic.c +4
-1}else apic_clear_vector (vector, apic->regs +APIC_TMR ); - result = !apic_test_and_set_irr (vector, apic); + result =1 ; +if (!kvm_x86_ops->deliver_posted_interrupt (vcpu, vector)) + result = !apic_test_and_set_irr (vector, apic); +trace_kvm_apic_accept_irq (vcpu->vcpu_id, delivery_mode, trig_mode, vector, !result);if (!result) {@@ -723,8 +726,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, · line 733
Quoted 9 lines
arch/x86/kvm/lapic.c +4
-2break ; } -kvm_make_request (KVM_REQ_EVENT , vcpu); -kvm_vcpu_kick (vcpu); +if (!kvm_x86_ops->vm_has_apicv (vcpu->kvm)) { +kvm_make_request (KVM_REQ_EVENT , vcpu); +kvm_vcpu_kick (vcpu); + }break ;apicv code and non apicv code are completely different. What's the point checking for apicv twice here?
Just do:if (
kvm_x86_ops->deliver_posted_interrupt)kvm_x86_ops->deliver_posted_interrupt(vcpu, vector) else { result = !apic_test_and_set_irr(vector, apic); kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); }
Quoted 4 lines
And set
kvm_x86_ops->deliver_posted_interruptonly if apicv is enabled.Also rearrange patches so that
APIC_TMRhandling goes before posted interrupt series.
Sure.
Quoted 42 lines
arch/x86/kvm/vmx.c static void vmx_posted_intr_clear_on(struct
Quoted 28 lines
arch/x86/kvm/lapic.c +5
-0case APIC_DM_REMRD: @@ -1604,6 +1609,11 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) return highest_irr; } +bool kvm_hwapic_has_interrupt (struct kvm_vcpu *vcpu) +{ +return kvm_x86_ops->hwapic_has_interrupt (vcpu); +} +int kvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu) {u32 lvt0 =kvm_apic_get_reg (vcpu->arch.apic,APIC_LVT0 );arch/x86/kvm/lapic.h +0
-0@@ -37,6 +37,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);void kvm_free_lapic (struct kvm_vcpu *vcpu); int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); +bool kvm_hwapic_has_interrupt(struct kvm_vcpu *vcpu); intkvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu);int kvm_get_apic_interrupt (struct kvm_vcpu *vcpu);void kvm_lapic_reset (struct kvm_vcpu *vcpu);arch/x86/kvm/vmx.c +0
-0@@ -3932,6 +3932,17 @@ static void vmx_posted_intr_clear_on(struct
kvm_vcpu*vcpu)arch/x86/kvm/vmx.c static void vmx_posted_intr_clear_on(struct kvm_vcpu *vcpu) · line 3945
Quoted 13 lines
arch/x86/kvm/vmx.c +11
-0clear_bit (POSTED_INTR_ON , (unsigned long *)&vmx->pi_desc.u.control); } +/* +* Send interrupt to vcpu via posted interrupt way. +* Return false if posted interrupt is not supported and the caller will +* roll back to old way(via set vIRR). +* Return true if posted interrupt is avalialbe, the interrupt is set +* in pir(posted interrupt requests): +* 1. If target vcpu is running(non-root mode), send posted interrupt +* notification to vcpu and hardware will sync pir to vIRR atomically. +* 2. If target vcpu isn't running(root mode), kick it to pick up the +* interrupt from pir in next vmentry. +*/
Quoted 3 lines
The comment should go into previous patch. Also I prefer to not check for posted interrupt inside the callback, but set it to NULL instead. This way we avoid calling a callback on a hot path needlessly.
It's make sense. So just follow the logic you mentioned above?
Quoted 18 lines
Quoted 18 lines
arch/x86/kvm/vmx.c +0
-0static bool vmx_deliver_posted_interrupt (struct kvm_vcpu *vcpu,int vector) {struct vcpu_vmx *vmx =to_vmx (vcpu);arch/x86/kvm/x86.c +0
-0@@ -2679,6 +2679,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)static int kvm_vcpu_ioctl_get_lapic (struct kvm_vcpu *vcpu,struct kvm_lapic_state *s) { + kvm_x86_ops->sync_pir_to_irr (vcpu);memcpy (s->regs, vcpu->arch.apic->regs,sizeof *s); return 0; @@ -5699,6 +5700,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) }if (kvm_check_request (KVM_REQ_EVENT , vcpu) || req_int_win) { + kvm_x86_ops->sync_pir_to_irr (vcpu);inject_pending_event (vcpu);
Quoted 7 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5746
Quoted 6 lines
arch/x86/kvm/x86.c +2
-0/* enable NMI/IRQ window open exits if needed */ @@ -5741,6 +5743,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +Why is this separate from
pir_to_irrsyncing?
This is the result of discussion with Marcelo.
It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode = IN_GUEST_MODE;
<--interrupt may arrived here and this is unnecessary.
local_irq_disable();
Quoted 8 lines
Quoted 5 lines
arch/x86/kvm/x86.c +0
-1if (vcpu->mode ==EXITING_GUEST_MODE || vcpu->requests ||need_resched () ||signal_pending (current)) { vcpu->mode =OUTSIDE_GUEST_MODE ; --1.7.1
--
Gleb.
Best regards,
Yang
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 119 lines · Yang Z
Gleb Natapov wrote on 2013-03-19:
Quoted 19 lines · Yang Zhang
Quoted 18 lines
From: Yang Zhang <[email protected]>
If posted interrupt is avaliable, then uses it to inject virtual interrupt to guest.
Signed-off-by Yang Zhang <[email protected]>--- arch/x86/kvm/irq.c | 3 ++- arch/x86/kvm/lapic.c | 16 +++++++++++++--- arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/vmx.c | 11 +++++++++++ arch/x86/kvm/x86.c | 4 ++++ 5 files changed, 31 insertions(+), 4 deletions(-)arch/x86/kvm/irq.c +0
-0@@ -81,7 +81,8 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)Quoted 8 lines
arch/x86/kvm/irq.c int kvm_cpu_has_interrupt(struct kvm_vcpu *v) · line 85
Quoted 5 lines
arch/x86/kvm/irq.c +2
-1if (kvm_cpu_has_extint (v))return 1 ; -return kvm_apic_has_interrupt (v) !=-1 ;/* LAPIC */ +return (kvm_apic_has_interrupt (v) !=-1 ) || +kvm_hwapic_has_interrupt (v);That's incorrect.
kvm_cpu_has_interrupt()should return true only it there is IRR suitable to be injected, not just any IRR.kvm_apic_has_interrupt()should callkvm_apic_update_irr().You are right.
Quoted 41 lines
arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int
Quoted 7 lines
arch/x86/kvm/irq.c +0
-0}EXPORT_SYMBOL_GPL (kvm_cpu_has_interrupt);arch/x86/kvm/lapic.c +0
-0@@ -713,7 +713,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int
Quoted 11 lines
arch/x86/kvm/lapic.c +4
-1}else apic_clear_vector (vector, apic->regs +APIC_TMR ); - result = !apic_test_and_set_irr (vector, apic); + result =1 ; +if (!kvm_x86_ops->deliver_posted_interrupt (vcpu, vector)) + result = !apic_test_and_set_irr (vector, apic); +trace_kvm_apic_accept_irq (vcpu->vcpu_id, delivery_mode, trig_mode, vector, !result);if (!result) {@@ -723,8 +726,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, · line 733
Quoted 9 lines
arch/x86/kvm/lapic.c +4
-2break ; } -kvm_make_request (KVM_REQ_EVENT , vcpu); -kvm_vcpu_kick (vcpu); +if (!kvm_x86_ops->vm_has_apicv (vcpu->kvm)) { +kvm_make_request (KVM_REQ_EVENT , vcpu); +kvm_vcpu_kick (vcpu); + }break ;apicv code and non apicv code are completely different. What's the point checking for apicv twice here?
Just do:if (
kvm_x86_ops->deliver_posted_interrupt)kvm_x86_ops->deliver_posted_interrupt(vcpu, vector) else { result = !apic_test_and_set_irr(vector, apic); kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); }Quoted 4 lines
And set
kvm_x86_ops->deliver_posted_interruptonly if apicv is enabled.Also rearrange patches so that
APIC_TMRhandling goes before posted interrupt series.Sure.
Quoted 42 lines
arch/x86/kvm/vmx.c static void vmx_posted_intr_clear_on(struct
Quoted 28 lines
arch/x86/kvm/lapic.c +5
-0case APIC_DM_REMRD: @@ -1604,6 +1609,11 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) return highest_irr; } +bool kvm_hwapic_has_interrupt (struct kvm_vcpu *vcpu) +{ +return kvm_x86_ops->hwapic_has_interrupt (vcpu); +} +int kvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu) {u32 lvt0 =kvm_apic_get_reg (vcpu->arch.apic,APIC_LVT0 );arch/x86/kvm/lapic.h +0
-0@@ -37,6 +37,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);void kvm_free_lapic (struct kvm_vcpu *vcpu); int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); +bool kvm_hwapic_has_interrupt(struct kvm_vcpu *vcpu); intkvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu);int kvm_get_apic_interrupt (struct kvm_vcpu *vcpu);void kvm_lapic_reset (struct kvm_vcpu *vcpu);arch/x86/kvm/vmx.c +0
-0@@ -3932,6 +3932,17 @@ static void vmx_posted_intr_clear_on(struct
kvm_vcpu*vcpu)Quoted 13 lines
arch/x86/kvm/vmx.c +11
-0clear_bit (POSTED_INTR_ON , (unsigned long *)&vmx->pi_desc.u.control); } +/* +* Send interrupt to vcpu via posted interrupt way. +* Return false if posted interrupt is not supported and the caller will +* roll back to old way(via set vIRR). +* Return true if posted interrupt is avalialbe, the interrupt is set +* in pir(posted interrupt requests): +* 1. If target vcpu is running(non-root mode), send posted interrupt +* notification to vcpu and hardware will sync pir to vIRR atomically. +* 2. If target vcpu isn't running(root mode), kick it to pick up the +* interrupt from pir in next vmentry. +*/
Quoted 5 lines
Quoted 3 lines
The comment should go into previous patch. Also I prefer to not check for posted interrupt inside the callback, but set it to NULL instead. This way we avoid calling a callback on a hot path needlessly.
It's make sense. So just follow the logic you mentioned above?
Yes.
Quoted 25 lines
Quoted 18 lines
Quoted 18 lines
arch/x86/kvm/vmx.c +0
-0static bool vmx_deliver_posted_interrupt (struct kvm_vcpu *vcpu,int vector) {struct vcpu_vmx *vmx =to_vmx (vcpu);arch/x86/kvm/x86.c +0
-0@@ -2679,6 +2679,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)static int kvm_vcpu_ioctl_get_lapic (struct kvm_vcpu *vcpu,struct kvm_lapic_state *s) { + kvm_x86_ops->sync_pir_to_irr (vcpu);memcpy (s->regs, vcpu->arch.apic->regs,sizeof *s); return 0; @@ -5699,6 +5700,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) }if (kvm_check_request (KVM_REQ_EVENT , vcpu) || req_int_win) { + kvm_x86_ops->sync_pir_to_irr (vcpu);inject_pending_event (vcpu);Quoted 7 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5746
Quoted 6 lines
arch/x86/kvm/x86.c +2
-0/* enable NMI/IRQ window open exits if needed */ @@ -5741,6 +5743,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +Why is this separate from
pir_to_irrsyncing?
Quoted 9 lines
This is the result of discussion with Marcelo.
It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();
But this still can happen as far as I see:
vcpu0 vcpu1:pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)
if (KVM_REQ_EVENT)
sync_pir_to_irr()
vcpu->mode = IN_GUEST_MODE;
if (vcpu->mode == IN_GUEST_MODE)
if (!pi_test_and_set_on())
apic->send_IPI_mask()
--> IPI arrives here
local_irq_disable();
posted_intr_clear_on()May be move vcpu->mode = IN_GUEST_MODE after local_irq_disable()?
--
Gleb.
RE: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Gleb Natapov wrote on 2013-03-19:
Quoted 170 lines · Yang Z
Quoted 30 lines
Gleb Natapov wrote on 2013-03-19:
Quoted 19 lines · Yang Zhang
Quoted 18 lines
From: Yang Zhang <[email protected]>
If posted interrupt is avaliable, then uses it to inject virtual interrupt to guest.
Signed-off-by Yang Zhang <[email protected]>--- arch/x86/kvm/irq.c | 3 ++- arch/x86/kvm/lapic.c | 16 +++++++++++++--- arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/vmx.c | 11 +++++++++++ arch/x86/kvm/x86.c | 4 ++++ 5 files changed, 31 insertions(+), 4 deletions(-)arch/x86/kvm/irq.c +0
-0@@ -81,7 +81,8 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)Quoted 8 lines
arch/x86/kvm/irq.c int kvm_cpu_has_interrupt(struct kvm_vcpu *v) · line 85
Quoted 5 lines
arch/x86/kvm/irq.c +2
-1if (kvm_cpu_has_extint (v))return 1 ; -return kvm_apic_has_interrupt (v) !=-1 ;/* LAPIC */ +return (kvm_apic_has_interrupt (v) !=-1 ) || +kvm_hwapic_has_interrupt (v);That's incorrect.
kvm_cpu_has_interrupt()should return true only it there is IRR suitable to be injected, not just any IRR.kvm_apic_has_interrupt()should callkvm_apic_update_irr().You are right.
Quoted 7 lines
Quoted 7 lines
arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic,
Quoted 7 lines
arch/x86/kvm/irq.c +0
-0}EXPORT_SYMBOL_GPL (kvm_cpu_has_interrupt);arch/x86/kvm/lapic.c +0
-0@@ -713,7 +713,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic,int
Quoted 12 lines
Quoted 12 lines
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic,
Quoted 11 lines
arch/x86/kvm/lapic.c +4
-1}else apic_clear_vector (vector, apic->regs +APIC_TMR ); - result = !apic_test_and_set_irr (vector, apic); + result =1 ; +if (!kvm_x86_ops->deliver_posted_interrupt (vcpu, vector)) + result = !apic_test_and_set_irr (vector, apic); +trace_kvm_apic_accept_irq (vcpu->vcpu_id, delivery_mode, trig_mode, vector, !result);if (!result) {@@ -723,8 +726,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic,int
Quoted 70 lines
Quoted 22 lines
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, · line 733
Quoted 9 lines
arch/x86/kvm/lapic.c +4
-2break ; } -kvm_make_request (KVM_REQ_EVENT , vcpu); -kvm_vcpu_kick (vcpu); +if (!kvm_x86_ops->vm_has_apicv (vcpu->kvm)) { +kvm_make_request (KVM_REQ_EVENT , vcpu); +kvm_vcpu_kick (vcpu); + }break ;apicv code and non apicv code are completely different. What's the point checking for apicv twice here?
Just do:if (
kvm_x86_ops->deliver_posted_interrupt)kvm_x86_ops->deliver_posted_interrupt(vcpu, vector) else { result = !apic_test_and_set_irr(vector, apic); kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); }Quoted 4 lines
And set
kvm_x86_ops->deliver_posted_interruptonly if apicv is enabled.Also rearrange patches so that
APIC_TMRhandling goes before posted interrupt series.Sure.
Quoted 42 lines
arch/x86/kvm/vmx.c static void vmx_posted_intr_clear_on(struct
Quoted 28 lines
arch/x86/kvm/lapic.c +5
-0case APIC_DM_REMRD: @@ -1604,6 +1609,11 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) return highest_irr; } +bool kvm_hwapic_has_interrupt (struct kvm_vcpu *vcpu) +{ +return kvm_x86_ops->hwapic_has_interrupt (vcpu); +} +int kvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu) {u32 lvt0 =kvm_apic_get_reg (vcpu->arch.apic,APIC_LVT0 );arch/x86/kvm/lapic.h +0
-0@@ -37,6 +37,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);void kvm_free_lapic (struct kvm_vcpu *vcpu); int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); +bool kvm_hwapic_has_interrupt(struct kvm_vcpu *vcpu); intkvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu);int kvm_get_apic_interrupt (struct kvm_vcpu *vcpu);void kvm_lapic_reset (struct kvm_vcpu *vcpu);arch/x86/kvm/vmx.c +0
-0@@ -3932,6 +3932,17 @@ static void vmx_posted_intr_clear_on(struct
kvm_vcpu*vcpu)Quoted 13 lines
arch/x86/kvm/vmx.c +11
-0clear_bit (POSTED_INTR_ON , (unsigned long *)&vmx->pi_desc.u.control); } +/* +* Send interrupt to vcpu via posted interrupt way. +* Return false if posted interrupt is not supported and the caller will +* roll back to old way(via set vIRR). +* Return true if posted interrupt is avalialbe, the interrupt is set +* in pir(posted interrupt requests): +* 1. If target vcpu is running(non-root mode), send posted interrupt +* notification to vcpu and hardware will sync pir to vIRR atomically. +* 2. If target vcpu isn't running(root mode), kick it to pick up the +* interrupt from pir in next vmentry. +*/ Quoted 5 lines
Quoted 3 lines
The comment should go into previous patch. Also I prefer to not check for posted interrupt inside the callback, but set it to NULL instead. This way we avoid calling a callback on a hot path needlessly.
It's make sense. So just follow the logic you mentioned above?
Yes.
Quoted 9 lines
Quoted 9 lines
Quoted 9 lines
arch/x86/kvm/vmx.c +0
-0static bool vmx_deliver_posted_interrupt (struct kvm_vcpu *vcpu,int vector) {struct vcpu_vmx *vmx =to_vmx (vcpu);arch/x86/kvm/x86.c +0
-0@@ -2679,6 +2679,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) static int kvm_vcpu_ioctl_get_lapic(struct kvm_vcpu *vcpu,Quoted 8 lines
Quoted 8 lines
arch/x86/kvm/x86.c void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
Quoted 8 lines
arch/x86/kvm/x86.c +0
-0struct kvm_lapic_state *s) { + kvm_x86_ops->sync_pir_to_irr(vcpu);memcpy (s->regs, vcpu->arch.apic->regs,sizeof *s); return 0; @@ -5699,6 +5700,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) }if (kvm_check_request (KVM_REQ_EVENT , vcpu) || req_int_win) { + kvm_x86_ops->sync_pir_to_irr (vcpu);inject_pending_event(vcpu);Quoted 9 lines
Quoted 9 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu · line 5747
Quoted 8 lines
arch/x86/kvm/x86.c +2
-0/* enable NMI/IRQ window open exits if needed */ @@ -5741,6 +5743,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo. It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)
Quoted 10 lines
if (KVM_REQ_EVENT)
sync_pir_to_irr()
vcpu->mode =
IN_GUEST_MODE;
if (vcpu->mode == IN_GUEST_MODE)
if (!pi_test_and_set_on())
apic->send_IPI_mask()
--> IPI arrives here
local_irq_disable();
posted_intr_clear_on()Current solution is trying to block other Posted Interrupt from other VCPUs at same time. It only mitigates it but cannot solve it. The case you mentioned still exists but it should be rare.
Quoted 1 line
May be move
vcpu->mode=IN_GUEST_MODEafterlocal_irq_disable()?
Yes, this will solve it. But I am not sure whether it will introduce any regressions. Is there any check relies on this sequence?
Quoted 2 lines
--
Gleb.
Best regards,
Yang
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 28 lines · Yang Z
Quoted 18 lines
Quoted 4 lines
Quoted 4 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5747
Quoted 3 lines
arch/x86/kvm/x86.c +2
-0local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo. It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)Quoted 10 lines
if (KVM_REQ_EVENT) sync_pir_to_irr() vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()
Quoted 2 lines
Current solution is trying to block other Posted Interrupt from other VCPUs at same time. It only mitigates it but cannot solve it. The case you mentioned still exists but it should be rare.
I am not sure I follow. What scenario exactly are you talking about. I looked over past discussion about it and saw that Marcelo gives an example how IPI can be lost, but I think that's because we set "on" bit after KVM_REQ_EVENT:
cpu0 cpu1 vcpu0test_and_set_bit(PIR-A)
set KVM_REQ_EVENT
process REQ_EVENT
PIR-A->IRR
vcpu->mode=IN_GUESTif (vcpu0->guest_mode)
if (!t_a_s_bit(PIR notif))
send IPI
linux_pir_handler
t_a_s_b(PIR-B)=1
no PIR IPI sentBut what if on delivery we do:pi_test_and_set_pir()
r = pi_test_and_set_on()kvm_make_request(KVM_REQ_EVENT)
if (!r)
send_IPI_mask()
else
kvm_vcpu_kick()
And on vcpu entry we do:
if (kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()
What are the downsides? Can we lost interrupts this way?
Quoted 3 lines
Quoted 1 line
May be move
vcpu->mode=IN_GUEST_MODEafterlocal_irq_disable()?Yes, this will solve it. But I am not sure whether it will introduce any regressions. Is there any check relies on this sequence?
Do not think so.
--
Gleb.
RE: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Gleb Natapov wrote on 2013-03-19:
Quoted 29 lines · Yang Z
Quoted 28 lines
Quoted 28 lines
Quoted 4 lines
Quoted 4 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5747
Quoted 3 lines
arch/x86/kvm/x86.c +2
-0local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo. It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)if (KVM_REQ_EVENT) sync_pir_to_irr() vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()
Quoted 8 lines
Quoted 1 line
Current solution is trying to block other Posted Interrupt from other VCPUs at
same time. It only mitigates it but cannot solve it. The case you mentioned still exists but it should be rare.
Quoted 1 line
I am not sure I follow. What scenario exactly are you talking about. I looked over past discussion about it and saw that Marcelo gives an example how IPI can be lost, but I think that's because we set "on" bit after
KVM_REQ_EVENT:
The IPI will not lost in his example(he misread the patch).
Quoted 16 lines
cpu0 cpu1 vcpu0
test_and_set_bit(PIR-A)setKVM_REQ_EVENTprocess REQ_EVENT PIR-A->IRRvcpu->mode=IN_GUEST
if (
vcpu0->guest_mode)if (!t_a_s_bit(PIR notif)) send IPI
linux_pir_handlert_a_s_b(PIR-B)=1 no PIR IPI sent
Quoted 11 lines
But what if on delivery we do:
pi_test_and_set_pir()
r =pi_test_and_set_on()kvm_make_request(KVM_REQ_EVENT)
if (!r)
send_IPI_mask()elsekvm_vcpu_kick()
And on vcpu entry we do:
if (kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()
What are the downsides? Can we lost interrupts this way?
Need to check guest mode before sending IPI. Otherwise hypervisor may receive IPI.
I think current logic is ok. Only problem is that when to clear Outstanding Notification bit. Actually I prefer your suggestion to clear it before sync_pir_irr. But Marcelo prefer to clear ON bit after disabling irq.
Quoted 8 lines
Quoted 4 lines
Quoted 1 line
May be move
vcpu->mode=IN_GUEST_MODEafterlocal_irq_disable()?Yes, this will solve it. But I am not sure whether it will introduce any regressions. Is there any check relies on this sequence?
Do not think so.
--
Gleb.
Best regards,
Yang
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 67 lines · Yang Z
Gleb Natapov wrote on 2013-03-19:
Quoted 29 lines · Yang Z
Quoted 28 lines
Quoted 28 lines
Quoted 4 lines
Quoted 4 lines
Review
Quoted 3 lines
(quoted diff) +2
-0local_irq_disable(); + kvm_x86_ops->posted_intr_clear_on(vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo. It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)if (KVM_REQ_EVENT) sync_pir_to_irr() vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()Quoted 8 lines
Quoted 1 line
Current solution is trying to block other Posted Interrupt from other VCPUs at
same time. It only mitigates it but cannot solve it. The case you mentioned still exists but it should be rare.
Quoted 1 line
I am not sure I follow. What scenario exactly are you talking about. I looked over past discussion about it and saw that Marcelo gives an example how IPI can be lost, but I think that's because we set "on" bit after
KVM_REQ_EVENT:The IPI will not lost in his example(he misread the patch).
Quoted 16 lines
cpu0 cpu1 vcpu0
test_and_set_bit(PIR-A)setKVM_REQ_EVENTprocess REQ_EVENT PIR-A->IRRvcpu->mode=IN_GUEST
if (
vcpu0->guest_mode)if (!t_a_s_bit(PIR notif)) send IPI
linux_pir_handlert_a_s_b(PIR-B)=1 no PIR IPI sent
Quoted 11 lines
But what if on delivery we do:
pi_test_and_set_pir()
r =pi_test_and_set_on()kvm_make_request(KVM_REQ_EVENT)
if (!r)
send_IPI_mask()elsekvm_vcpu_kick()
And on vcpu entry we do:
if (kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()
What are the downsides? Can we lost interrupts this way?
Quoted 1 line
Need to check guest mode before sending IPI. Otherwise hypervisor may receive IPI.
Of course, forget it. So if (!r) should be if (!r && mode == IN_GUEST)
Quoted 1 line
I think current logic is ok. Only problem is that when to clear Outstanding Notification bit. Actually I prefer your suggestion to clear it before
sync_pir_irr. But Marcelo prefer to clear ON bit after disabling irq.
Marcelo what is the problem with the logic above?
--
Gleb.
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 68 lines · Gleb Natapov
Quoted 67 lines · Yang Z
Gleb Natapov wrote on 2013-03-19:
Quoted 29 lines · Yang Z
Quoted 28 lines
Quoted 28 lines
Quoted 4 lines
Quoted 4 lines
Review
Quoted 3 lines
(quoted diff) +2
-0local_irq_disable(); + kvm_x86_ops->posted_intr_clear_on(vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo. It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)if (KVM_REQ_EVENT) sync_pir_to_irr() vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()Quoted 8 lines
Quoted 1 line
Current solution is trying to block other Posted Interrupt from other VCPUs at
same time. It only mitigates it but cannot solve it. The case you mentioned still exists but it should be rare.
Quoted 1 line
I am not sure I follow. What scenario exactly are you talking about. I looked over past discussion about it and saw that Marcelo gives an example how IPI can be lost, but I think that's because we set "on" bit after
KVM_REQ_EVENT:The IPI will not lost in his example(he misread the patch).
Quoted 27 lines
cpu0 cpu1 vcpu0
test_and_set_bit(PIR-A)setKVM_REQ_EVENTprocess REQ_EVENT PIR-A->IRRvcpu->mode=IN_GUEST
if (
vcpu0->guest_mode)if (!t_a_s_bit(PIR notif)) send IPI
linux_pir_handlert_a_s_b(PIR-B)=1 no PIR IPI sent
But what if on delivery we do:
pi_test_and_set_pir()
r =pi_test_and_set_on()kvm_make_request(KVM_REQ_EVENT)
if (!r)
send_IPI_mask()elsekvm_vcpu_kick()
And on vcpu entry we do:
if (kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()
What are the downsides? Can we lost interrupts this way?
Quoted 6 lines
Quoted 1 line
Need to check guest mode before sending IPI. Otherwise hypervisor may receive IPI.
Of course, forget it. So if (!r) should be if (!r && mode ==
IN_GUEST)Quoted 1 line
I think current logic is ok. Only problem is that when to clear Outstanding Notification bit. Actually I prefer your suggestion to clear it before
sync_pir_irr. But Marcelo prefer to clear ON bit after disabling irq.Marcelo what is the problem with the logic above?
Just to clarify the advantages that I see are: one less callback, no need to sync pir to irr on each event and, arguably, a little bit simpler logic.
--
Gleb.
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 70 lines · Gleb Natapov
Quoted 69 lines · Gleb Natapov
Quoted 68 lines · Yang Z
Gleb Natapov wrote on 2013-03-19:
Quoted 29 lines · Yang Z
Quoted 28 lines
Quoted 28 lines
Quoted 4 lines
Quoted 4 lines
Review
Quoted 3 lines
(quoted diff) +2
-0local_irq_disable(); + kvm_x86_ops->posted_intr_clear_on(vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo. It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)if (KVM_REQ_EVENT) sync_pir_to_irr() vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()Quoted 8 lines
Quoted 1 line
Current solution is trying to block other Posted Interrupt from other VCPUs at
same time. It only mitigates it but cannot solve it. The case you mentioned still exists but it should be rare.
Quoted 1 line
I am not sure I follow. What scenario exactly are you talking about. I looked over past discussion about it and saw that Marcelo gives an example how IPI can be lost, but I think that's because we set "on" bit after
KVM_REQ_EVENT:The IPI will not lost in his example(he misread the patch).
Quoted 16 lines
cpu0 cpu1 vcpu0
test_and_set_bit(PIR-A)setKVM_REQ_EVENTprocess REQ_EVENT PIR-A->IRRvcpu->mode=IN_GUEST
if (
vcpu0->guest_mode)if (!t_a_s_bit(PIR notif)) send IPI
linux_pir_handlert_a_s_b(PIR-B)=1 no PIR IPI sent
Quoted 11 lines
But what if on delivery we do:
pi_test_and_set_pir()
r =pi_test_and_set_on()kvm_make_request(KVM_REQ_EVENT)
if (!r)
send_IPI_mask()elsekvm_vcpu_kick()
And on vcpu entry we do:
if (kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()
What are the downsides? Can we lost interrupts this way?Need to check guest mode before sending IPI. Otherwise hypervisor may receive IPI.
Quoted 8 lines
Quoted 5 lines
Of course, forget it. So if (!r) should be if (!r && mode ==
IN_GUEST)Quoted 1 line
I think current logic is ok. Only problem is that when to clear Outstanding Notification bit. Actually I prefer your suggestion to clear it before
sync_pir_irr. But Marcelo prefer to clear ON bit after disabling irq.Marcelo what is the problem with the logic above?
Just to clarify the advantages that I see are: one less callback, no need to sync pir to irr on each event and, arguably, a little bit simpler logic.
See the previous argument: should never enter guest mode with PIR ON bit set. With logic above:
context1 context2 context3
set_bit(PIR-1) r = pi_test_and_set_on() set_bit(PIR-40) set_bit(KVM_REQ_EVENT)
if (kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr() r = pi_test_and_set_on()
guest entry with PIR ON=1
Thats the reason for unconditional clearing on guest entry: it is easy to verify its correct. I understand and agree the callback (and VMWRITE) is not nice.
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 10 lines · Marcelo Tosatti
See the previous argument: should never enter guest mode with PIR ON bit set. With logic above:
context1 context2 context3
set_bit(PIR-1) r = pi_test_and_set_on() set_bit(PIR-40) set_bit(KVM_REQ_EVENT)if (
kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
Quoted 8 lines
kvm_apic_update_irr() r = pi_test_and_set_on()guest entry with PIR ON=1
Thats the reason for unconditional clearing on guest entry: it is easy to verify its correct. I understand and agree the callback (and VMWRITE) is not nice.
Re: KVM_REQ_EVENT setting after set_bit(KVM_REQ_EVENT) assures no guest entry with PIR ON=1.
Might be, would have to verify. Its trickier though. Maybe add a FIXME:
to the callback and remove it later.
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 20 lines · Marcelo Tosatti
Quoted 10 lines · Marcelo Tosatti
See the previous argument: should never enter guest mode with PIR ON bit set. With logic above:
context1 context2 context3
set_bit(PIR-1) r = pi_test_and_set_on() set_bit(PIR-40) set_bit(KVM_REQ_EVENT)if (
kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))Quoted 8 lines
kvm_apic_update_irr() r = pi_test_and_set_on()guest entry with PIR ON=1
Thats the reason for unconditional clearing on guest entry: it is easy to verify its correct. I understand and agree the callback (and VMWRITE) is not nice.
Quoted 5 lines
Re:
KVM_REQ_EVENTsetting afterset_bit(KVM_REQ_EVENT)assures no guest entry with PIR ON=1.Might be, would have to verify. Its trickier though. Maybe add a FIXME:
to the callback and remove it later.
We have time still. RTC series is not ready yet. I'll think hard and try to poke holes in the logic in this patch and you do the same for what I propose.
--
Gleb.
RE: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Gleb Natapov wrote on 2013-03-20:
Quoted 21 lines · Marcelo Tosatti
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines
See the previous argument: should never enter guest mode with PIR ON bit set. With logic above:
context1 context2 context3
set_bit(PIR-1) r = pi_test_and_set_on() set_bit(PIR-40) set_bit(KVM_REQ_EVENT)if (
kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()r =
pi_test_and_set_on()Quoted 8 lines
Quoted 7 lines
guest entry with PIR ON=1
Thats the reason for unconditional clearing on guest entry: it is easy to verify its correct. I understand and agree the callback (and VMWRITE) is not nice.
Quoted 8 lines
Quoted 5 lines
Re:
KVM_REQ_EVENTsetting afterset_bit(KVM_REQ_EVENT)assures no guest entry with PIR ON=1.Might be, would have to verify. Its trickier though. Maybe add a FIXME:
to the callback and remove it later.We have time still. RTC series is not ready yet. I'll think hard and try to poke holes in the logic in this patch and you do the same for what I propose.
Any thought? As far as I see, the two solutions are ok. It's hard to say which is better. But clear ON bit when sync_pir_irr should be more clear and close to hardware's behavior.
Best regards,
Yang
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 25 lines · Yang Z
Gleb Natapov wrote on 2013-03-20:
Quoted 24 lines · Marcelo Tosatti
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines
See the previous argument: should never enter guest mode with PIR ON bit set. With logic above:
context1 context2 context3
set_bit(PIR-1) r = pi_test_and_set_on() set_bit(PIR-40) set_bit(KVM_REQ_EVENT)if (
kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()r =
pi_test_and_set_on()Quoted 11 lines
Quoted 7 lines
guest entry with PIR ON=1
Thats the reason for unconditional clearing on guest entry: it is easy to verify its correct. I understand and agree the callback (and VMWRITE) is not nice.
Re:
KVM_REQ_EVENTsetting afterset_bit(KVM_REQ_EVENT)assures no guest entry with PIR ON=1.
Quoted 7 lines
Quoted 5 lines
Quoted 2 lines
Might be, would have to verify. Its trickier though. Maybe add a FIXME:
to the callback and remove it later.We have time still. RTC series is not ready yet. I'll think hard and try to poke holes in the logic in this patch and you do the same for what I propose.
Any thought? As far as I see, the two solutions are ok. It's hard to say which is better. But clear ON bit when
sync_pir_irrshould be more clear and close to hardware's behavior.
Lets go with it unless we see why it will not work.
--
Gleb.
RE: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Gleb Natapov wrote on 2013-03-20:
Quoted 28 lines · Yang Z
Quoted 27 lines
Gleb Natapov wrote on 2013-03-20:
Quoted 26 lines · Marcelo Tosatti
Quoted 11 lines · Marcelo Tosatti
Quoted 10 lines
See the previous argument: should never enter guest mode with PIR ON bit set. With logic above:
context1 context2 context3
set_bit(PIR-1) r = pi_test_and_set_on() set_bit(PIR-40) set_bit(KVM_REQ_EVENT)if (
kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()r =
pi_test_and_set_on()Quoted 13 lines
Quoted 7 lines
guest entry with PIR ON=1
Thats the reason for unconditional clearing on guest entry: it is easy to verify its correct. I understand and agree the callback (and VMWRITE) is not nice.
Re:
KVM_REQ_EVENTsetting afterset_bit(KVM_REQ_EVENT)assures no guest entry with PIR ON=1.Might be, would have to verify. Its trickier though. Maybe add a FIXME:
to the callback and remove it later.
Quoted 8 lines
Quoted 4 lines
Quoted 3 lines
We have time still. RTC series is not ready yet. I'll think hard and try to poke holes in the logic in this patch and you do the same for what I propose.
Any thought? As far as I see, the two solutions are ok. It's hard to say which is
better. But clear ON bit when
sync_pir_irrshould be more clear and close to hardware's behavior.Quoted 1 line
Lets go with it unless we see why it will not work.
Sure.
Best regards,
Yang
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
In reply to Marcelo TosattiQuoted 87 lines · Marcelo Tosatti
Quoted 70 lines · Gleb Natapov
Quoted 69 lines · Gleb Natapov
Quoted 68 lines · Yang Z
Gleb Natapov wrote on 2013-03-19:
Quoted 29 lines · Yang Z
Quoted 28 lines
Quoted 28 lines
Quoted 4 lines
Quoted 4 lines
Review
Quoted 3 lines
(quoted diff) +2
-0local_irq_disable(); + kvm_x86_ops->posted_intr_clear_on(vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo. It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)if (KVM_REQ_EVENT) sync_pir_to_irr() vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()Quoted 8 lines
Quoted 1 line
Current solution is trying to block other Posted Interrupt from other VCPUs at
same time. It only mitigates it but cannot solve it. The case you mentioned still exists but it should be rare.
Quoted 1 line
I am not sure I follow. What scenario exactly are you talking about. I looked over past discussion about it and saw that Marcelo gives an example how IPI can be lost, but I think that's because we set "on" bit after
KVM_REQ_EVENT:The IPI will not lost in his example(he misread the patch).
Quoted 16 lines
cpu0 cpu1 vcpu0
test_and_set_bit(PIR-A)setKVM_REQ_EVENTprocess REQ_EVENT PIR-A->IRRvcpu->mode=IN_GUEST
if (
vcpu0->guest_mode)if (!t_a_s_bit(PIR notif)) send IPI
linux_pir_handlert_a_s_b(PIR-B)=1 no PIR IPI sent
Quoted 11 lines
But what if on delivery we do:
pi_test_and_set_pir()
r =pi_test_and_set_on()kvm_make_request(KVM_REQ_EVENT)
if (!r)
send_IPI_mask()elsekvm_vcpu_kick()
And on vcpu entry we do:
if (kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()
What are the downsides? Can we lost interrupts this way?Need to check guest mode before sending IPI. Otherwise hypervisor may receive IPI.
Quoted 8 lines
Quoted 5 lines
Of course, forget it. So if (!r) should be if (!r && mode ==
IN_GUEST)Quoted 1 line
I think current logic is ok. Only problem is that when to clear Outstanding Notification bit. Actually I prefer your suggestion to clear it before
sync_pir_irr. But Marcelo prefer to clear ON bit after disabling irq.Marcelo what is the problem with the logic above?
Just to clarify the advantages that I see are: one less callback, no need to sync pir to irr on each event and, arguably, a little bit simpler logic.
See the previous argument: should never enter guest mode with PIR ON bit set. With logic above:
context1 context2 context3
set_bit(PIR-1) r = pi_test_and_set_on() set_bit(PIR-40) set_bit(KVM_REQ_EVENT)
Quoted 8 lines
if (
kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))kvm_apic_update_irr() r = pi_test_and_set_on()guest entry with PIR ON=1
But that's OK since context3 will send IPI and PIR will be processed by CPU. Let me amend myself: we should not enter guest mode with ON bit set and no PI IPI pending in LAPIC.
Quoted 3 lines
Thats the reason for unconditional clearing on guest entry: it is easy to verify its correct. I understand and agree the callback (and VMWRITE) is not nice.
--
Gleb.
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
In reply to Gleb NatapovQuoted 62 lines · Gleb Natapov
Quoted 28 lines · Yang Z
Quoted 18 lines
Quoted 4 lines
Quoted 4 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5747
Quoted 3 lines
arch/x86/kvm/x86.c +2
-0local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo. It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)Quoted 10 lines
if (KVM_REQ_EVENT) sync_pir_to_irr() vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()Quoted 2 lines
Current solution is trying to block other Posted Interrupt from other VCPUs at same time. It only mitigates it but cannot solve it. The case you mentioned still exists but it should be rare.
I am not sure I follow. What scenario exactly are you talking about. I looked over past discussion about it and saw that Marcelo gives an example how IPI can be lost, but I think that's because we set "on" bit after
KVM_REQ_EVENT:cpu0 cpu1 vcpu0
test_and_set_bit(PIR-A)
setKVM_REQ_EVENTprocess REQ_EVENT PIR-A->IRR vcpu->mode=IN_GUESTif (
vcpu0->guest_mode)if (!t_a_s_bit(PIR notif)) send IPI linux_pir_handler t_a_s_b(PIR-B)=1 no PIR IPI sentBut what if on delivery we do:
pi_test_and_set_pir()
r =pi_test_and_set_on()kvm_make_request(KVM_REQ_EVENT)
if (!r)
send_IPI_mask()
else
kvm_vcpu_kick()
Quoted 6 lines
And on vcpu entry we do:
if (kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()What are the downsides? Can we lost interrupts this way?
You should not ever enter guest mode with ON bit set on PIR (because that will prevent PIR IPI from waking up interrupt injection logic). This is why the ON bit should be cleared on VM entry.
Quoted 4 lines
Quoted 3 lines
Quoted 1 line
May be move
vcpu->mode=IN_GUEST_MODEafterlocal_irq_disable()?Yes, this will solve it. But I am not sure whether it will introduce any regressions. Is there any check relies on this sequence?
Do not think so.
Can't see what is the problem with the code as it is?
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 68 lines · Marcelo Tosatti
Quoted 67 lines · Gleb Natapov
Quoted 28 lines · Yang Z
Quoted 18 lines
Quoted 4 lines
Quoted 4 lines
Review
Quoted 3 lines
(quoted diff) +2
-0local_irq_disable(); + kvm_x86_ops->posted_intr_clear_on(vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo. It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)Quoted 10 lines
if (KVM_REQ_EVENT) sync_pir_to_irr() vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()Quoted 2 lines
Current solution is trying to block other Posted Interrupt from other VCPUs at same time. It only mitigates it but cannot solve it. The case you mentioned still exists but it should be rare.
I am not sure I follow. What scenario exactly are you talking about. I looked over past discussion about it and saw that Marcelo gives an example how IPI can be lost, but I think that's because we set "on" bit after
KVM_REQ_EVENT:cpu0 cpu1 vcpu0
test_and_set_bit(PIR-A)
setKVM_REQ_EVENTprocess REQ_EVENT PIR-A->IRR vcpu->mode=IN_GUESTif (
vcpu0->guest_mode)if (!t_a_s_bit(PIR notif)) send IPI linux_pir_handler t_a_s_b(PIR-B)=1 no PIR IPI sentBut what if on delivery we do:
pi_test_and_set_pir()
r =pi_test_and_set_on()kvm_make_request(KVM_REQ_EVENT)
if (!r)
send_IPI_mask()
else
kvm_vcpu_kick()And on vcpu entry we do:
if (kvm_check_request(KVM_REQ_EVENT)
if (test_and_clear_bit(on))
kvm_apic_update_irr()
Quoted 5 lines
Quoted 1 line
What are the downsides? Can we lost interrupts this way?
You should not ever enter guest mode with ON bit set on PIR (because that will prevent PIR IPI from waking up interrupt injection logic). This is why the ON bit should be cleared on VM entry.
I agree that we should not, but I claim that this will not happen since KVM_REQ_EVENT will prevent guest entry with ON bit set.
Quoted 8 lines
Quoted 5 lines
Quoted 4 lines
Quoted 2 lines
May be move
vcpu->mode=IN_GUEST_MODEafterlocal_irq_disable()?Yes, this will solve it. But I am not sure whether it will introduce any regressions. Is there any check relies on this sequence?
Do not think so.
Can't see what is the problem with the code as it is?
Just the useless IPI that can be prevented. I agree that this is not a big deal unless shown otherwise.
--
Gleb.
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
In reply to Gleb NatapovQuoted 162 lines · Gleb Natapov
Quoted 119 lines · Yang Z
Gleb Natapov wrote on 2013-03-19:
Quoted 19 lines · Yang Zhang
Quoted 18 lines
From: Yang Zhang <[email protected]>
If posted interrupt is avaliable, then uses it to inject virtual interrupt to guest.
Signed-off-by Yang Zhang <[email protected]>--- arch/x86/kvm/irq.c | 3 ++- arch/x86/kvm/lapic.c | 16 +++++++++++++--- arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/vmx.c | 11 +++++++++++ arch/x86/kvm/x86.c | 4 ++++ 5 files changed, 31 insertions(+), 4 deletions(-)arch/x86/kvm/irq.c +0
-0@@ -81,7 +81,8 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)Quoted 8 lines
arch/x86/kvm/irq.c int kvm_cpu_has_interrupt(struct kvm_vcpu *v) · line 85
Quoted 5 lines
arch/x86/kvm/irq.c +2
-1if (kvm_cpu_has_extint (v))return 1 ; -return kvm_apic_has_interrupt (v) !=-1 ;/* LAPIC */ +return (kvm_apic_has_interrupt (v) !=-1 ) || +kvm_hwapic_has_interrupt (v);That's incorrect.
kvm_cpu_has_interrupt()should return true only it there is IRR suitable to be injected, not just any IRR.kvm_apic_has_interrupt()should callkvm_apic_update_irr().You are right.
Quoted 41 lines
arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int
Quoted 7 lines
arch/x86/kvm/irq.c +0
-0}EXPORT_SYMBOL_GPL (kvm_cpu_has_interrupt);arch/x86/kvm/lapic.c +0
-0@@ -713,7 +713,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int
Quoted 11 lines
arch/x86/kvm/lapic.c +4
-1}else apic_clear_vector (vector, apic->regs +APIC_TMR ); - result = !apic_test_and_set_irr (vector, apic); + result =1 ; +if (!kvm_x86_ops->deliver_posted_interrupt (vcpu, vector)) + result = !apic_test_and_set_irr (vector, apic); +trace_kvm_apic_accept_irq (vcpu->vcpu_id, delivery_mode, trig_mode, vector, !result);if (!result) {@@ -723,8 +726,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, · line 733
Quoted 9 lines
arch/x86/kvm/lapic.c +4
-2break ; } -kvm_make_request (KVM_REQ_EVENT , vcpu); -kvm_vcpu_kick (vcpu); +if (!kvm_x86_ops->vm_has_apicv (vcpu->kvm)) { +kvm_make_request (KVM_REQ_EVENT , vcpu); +kvm_vcpu_kick (vcpu); + }break ;apicv code and non apicv code are completely different. What's the point checking for apicv twice here?
Just do:if (
kvm_x86_ops->deliver_posted_interrupt)kvm_x86_ops->deliver_posted_interrupt(vcpu, vector) else { result = !apic_test_and_set_irr(vector, apic); kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); }Quoted 4 lines
And set
kvm_x86_ops->deliver_posted_interruptonly if apicv is enabled.Also rearrange patches so that
APIC_TMRhandling goes before posted interrupt series.Sure.
Quoted 42 lines
arch/x86/kvm/vmx.c static void vmx_posted_intr_clear_on(struct
Quoted 28 lines
arch/x86/kvm/lapic.c +5
-0case APIC_DM_REMRD: @@ -1604,6 +1609,11 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) return highest_irr; } +bool kvm_hwapic_has_interrupt (struct kvm_vcpu *vcpu) +{ +return kvm_x86_ops->hwapic_has_interrupt (vcpu); +} +int kvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu) {u32 lvt0 =kvm_apic_get_reg (vcpu->arch.apic,APIC_LVT0 );arch/x86/kvm/lapic.h +0
-0@@ -37,6 +37,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);void kvm_free_lapic (struct kvm_vcpu *vcpu); int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); +bool kvm_hwapic_has_interrupt(struct kvm_vcpu *vcpu); intkvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu);int kvm_get_apic_interrupt (struct kvm_vcpu *vcpu);void kvm_lapic_reset (struct kvm_vcpu *vcpu);arch/x86/kvm/vmx.c +0
-0@@ -3932,6 +3932,17 @@ static void vmx_posted_intr_clear_on(struct
kvm_vcpu*vcpu)Quoted 13 lines
arch/x86/kvm/vmx.c +11
-0clear_bit (POSTED_INTR_ON , (unsigned long *)&vmx->pi_desc.u.control); } +/* +* Send interrupt to vcpu via posted interrupt way. +* Return false if posted interrupt is not supported and the caller will +* roll back to old way(via set vIRR). +* Return true if posted interrupt is avalialbe, the interrupt is set +* in pir(posted interrupt requests): +* 1. If target vcpu is running(non-root mode), send posted interrupt +* notification to vcpu and hardware will sync pir to vIRR atomically. +* 2. If target vcpu isn't running(root mode), kick it to pick up the +* interrupt from pir in next vmentry. +*/ Quoted 5 lines
Quoted 3 lines
The comment should go into previous patch. Also I prefer to not check for posted interrupt inside the callback, but set it to NULL instead. This way we avoid calling a callback on a hot path needlessly.
It's make sense. So just follow the logic you mentioned above?
Yes.
Quoted 25 lines
Quoted 18 lines
Quoted 18 lines
arch/x86/kvm/vmx.c +0
-0static bool vmx_deliver_posted_interrupt (struct kvm_vcpu *vcpu,int vector) {struct vcpu_vmx *vmx =to_vmx (vcpu);arch/x86/kvm/x86.c +0
-0@@ -2679,6 +2679,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)static int kvm_vcpu_ioctl_get_lapic (struct kvm_vcpu *vcpu,struct kvm_lapic_state *s) { + kvm_x86_ops->sync_pir_to_irr (vcpu);memcpy (s->regs, vcpu->arch.apic->regs,sizeof *s); return 0; @@ -5699,6 +5700,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) }if (kvm_check_request (KVM_REQ_EVENT , vcpu) || req_int_win) { + kvm_x86_ops->sync_pir_to_irr (vcpu);inject_pending_event (vcpu);Quoted 7 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5746
Quoted 6 lines
arch/x86/kvm/x86.c +2
-0/* enable NMI/IRQ window open exits if needed */ @@ -5741,6 +5743,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo.
It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();
Quoted 7 lines
But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)if (KVM_REQ_EVENT) sync_pir_to_irr()
^^^^^^^^^^^^^^^^^^
Quoted 10 lines
vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()May be move
vcpu->mode=IN_GUEST_MODEafterlocal_irq_disable()?
Scenario is correct because injected PIR has been synced to IRR before guest entry.
Re: [PATCH v6 5/5] KVM : VMX: Use posted interrupt to deliver virtual interrupt
Quoted 180 lines · Marcelo Tosatti
Quoted 162 lines · Gleb Natapov
Quoted 119 lines · Yang Z
Gleb Natapov wrote on 2013-03-19:
Quoted 19 lines · Yang Zhang
Quoted 18 lines
From: Yang Zhang <[email protected]>
If posted interrupt is avaliable, then uses it to inject virtual interrupt to guest.
Signed-off-by Yang Zhang <[email protected]>--- arch/x86/kvm/irq.c | 3 ++- arch/x86/kvm/lapic.c | 16 +++++++++++++--- arch/x86/kvm/lapic.h | 1 + arch/x86/kvm/vmx.c | 11 +++++++++++ arch/x86/kvm/x86.c | 4 ++++ 5 files changed, 31 insertions(+), 4 deletions(-)arch/x86/kvm/irq.c +0
-0@@ -81,7 +81,8 @@ int kvm_cpu_has_interrupt(struct kvm_vcpu *v)Quoted 8 lines
arch/x86/kvm/irq.c int kvm_cpu_has_interrupt(struct kvm_vcpu *v) · line 85
Quoted 5 lines
arch/x86/kvm/irq.c +2
-1if (kvm_cpu_has_extint (v))return 1 ; -return kvm_apic_has_interrupt (v) !=-1 ;/* LAPIC */ +return (kvm_apic_has_interrupt (v) !=-1 ) || +kvm_hwapic_has_interrupt (v);That's incorrect.
kvm_cpu_has_interrupt()should return true only it there is IRR suitable to be injected, not just any IRR.kvm_apic_has_interrupt()should callkvm_apic_update_irr().You are right.
Quoted 41 lines
arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int
Quoted 7 lines
arch/x86/kvm/irq.c +0
-0}EXPORT_SYMBOL_GPL (kvm_cpu_has_interrupt);arch/x86/kvm/lapic.c +0
-0@@ -713,7 +713,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int
Quoted 11 lines
arch/x86/kvm/lapic.c +4
-1}else apic_clear_vector (vector, apic->regs +APIC_TMR ); - result = !apic_test_and_set_irr (vector, apic); + result =1 ; +if (!kvm_x86_ops->deliver_posted_interrupt (vcpu, vector)) + result = !apic_test_and_set_irr (vector, apic); +trace_kvm_apic_accept_irq (vcpu->vcpu_id, delivery_mode, trig_mode, vector, !result);if (!result) {@@ -723,8 +726,10 @@ static int __apic_accept_irq(struct kvm_lapic *apic, int
delivery_mode,arch/x86/kvm/lapic.c static int __apic_accept_irq(struct kvm_lapic *apic, int delivery_mode, · line 733
Quoted 9 lines
arch/x86/kvm/lapic.c +4
-2break ; } -kvm_make_request (KVM_REQ_EVENT , vcpu); -kvm_vcpu_kick (vcpu); +if (!kvm_x86_ops->vm_has_apicv (vcpu->kvm)) { +kvm_make_request (KVM_REQ_EVENT , vcpu); +kvm_vcpu_kick (vcpu); + }break ;apicv code and non apicv code are completely different. What's the point checking for apicv twice here?
Just do:if (
kvm_x86_ops->deliver_posted_interrupt)kvm_x86_ops->deliver_posted_interrupt(vcpu, vector) else { result = !apic_test_and_set_irr(vector, apic); kvm_make_request(KVM_REQ_EVENT, vcpu); kvm_vcpu_kick(vcpu); }Quoted 4 lines
And set
kvm_x86_ops->deliver_posted_interruptonly if apicv is enabled.Also rearrange patches so that
APIC_TMRhandling goes before posted interrupt series.Sure.
Quoted 42 lines
arch/x86/kvm/vmx.c static void vmx_posted_intr_clear_on(struct
Quoted 28 lines
arch/x86/kvm/lapic.c +5
-0case APIC_DM_REMRD: @@ -1604,6 +1609,11 @@ int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu) return highest_irr; } +bool kvm_hwapic_has_interrupt (struct kvm_vcpu *vcpu) +{ +return kvm_x86_ops->hwapic_has_interrupt (vcpu); +} +int kvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu) {u32 lvt0 =kvm_apic_get_reg (vcpu->arch.apic,APIC_LVT0 );arch/x86/kvm/lapic.h +0
-0@@ -37,6 +37,7 @@ int kvm_create_lapic(struct kvm_vcpu *vcpu);void kvm_free_lapic (struct kvm_vcpu *vcpu); int kvm_apic_has_interrupt(struct kvm_vcpu *vcpu); +bool kvm_hwapic_has_interrupt(struct kvm_vcpu *vcpu); intkvm_apic_accept_pic_intr (struct kvm_vcpu *vcpu);int kvm_get_apic_interrupt (struct kvm_vcpu *vcpu);void kvm_lapic_reset (struct kvm_vcpu *vcpu);arch/x86/kvm/vmx.c +0
-0@@ -3932,6 +3932,17 @@ static void vmx_posted_intr_clear_on(struct
kvm_vcpu*vcpu)Quoted 13 lines
arch/x86/kvm/vmx.c +11
-0clear_bit (POSTED_INTR_ON , (unsigned long *)&vmx->pi_desc.u.control); } +/* +* Send interrupt to vcpu via posted interrupt way. +* Return false if posted interrupt is not supported and the caller will +* roll back to old way(via set vIRR). +* Return true if posted interrupt is avalialbe, the interrupt is set +* in pir(posted interrupt requests): +* 1. If target vcpu is running(non-root mode), send posted interrupt +* notification to vcpu and hardware will sync pir to vIRR atomically. +* 2. If target vcpu isn't running(root mode), kick it to pick up the +* interrupt from pir in next vmentry. +*/ Quoted 5 lines
Quoted 3 lines
The comment should go into previous patch. Also I prefer to not check for posted interrupt inside the callback, but set it to NULL instead. This way we avoid calling a callback on a hot path needlessly.
It's make sense. So just follow the logic you mentioned above?
Yes.
Quoted 25 lines
Quoted 18 lines
Quoted 18 lines
arch/x86/kvm/vmx.c +0
-0static bool vmx_deliver_posted_interrupt (struct kvm_vcpu *vcpu,int vector) {struct vcpu_vmx *vmx =to_vmx (vcpu);arch/x86/kvm/x86.c +0
-0@@ -2679,6 +2679,7 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)static int kvm_vcpu_ioctl_get_lapic (struct kvm_vcpu *vcpu,struct kvm_lapic_state *s) { + kvm_x86_ops->sync_pir_to_irr (vcpu);memcpy (s->regs, vcpu->arch.apic->regs,sizeof *s); return 0; @@ -5699,6 +5700,7 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) }if (kvm_check_request (KVM_REQ_EVENT , vcpu) || req_int_win) { + kvm_x86_ops->sync_pir_to_irr (vcpu);inject_pending_event (vcpu);Quoted 7 lines
arch/x86/kvm/x86.c static int vcpu_enter_guest(struct kvm_vcpu *vcpu) · line 5746
Quoted 6 lines
arch/x86/kvm/x86.c +2
-0/* enable NMI/IRQ window open exits if needed */ @@ -5741,6 +5743,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)local_irq_disable (); + kvm_x86_ops->posted_intr_clear_on (vcpu); +Why is this separate from
pir_to_irrsyncing?Quoted 9 lines
This is the result of discussion with Marcelo.
It is more reasonable to put it here to avoid unnecessary posted interrupt between:
vcpu->mode=IN_GUEST_MODE;<--interrupt may arrived here and this is unnecessary.
local_irq_disable();Quoted 7 lines
But this still can happen as far as I see:
vcpu0 vcpu1:
pi_test_and_set_pir()kvm_make_request(KVM_REQ_EVENT)if (KVM_REQ_EVENT) sync_pir_to_irr()^^^^^^^^^^^^^^^^^^Quoted 9 lines
vcpu->mode = IN_GUEST_MODE; if (vcpu->mode == IN_GUEST_MODE) if (!pi_test_and_set_on()) apic->send_IPI_mask() --> IPI arrives here local_irq_disable(); posted_intr_clear_on()
Quoted 4 lines
Quoted 1 line
May be move
vcpu->mode=IN_GUEST_MODEafterlocal_irq_disable()?Scenario is correct because injected PIR has been synced to IRR before guest entry.
I do not say it is not. Yang said that the code tries to prevent this from happening, I showed that this still can happen. There is not harm, just useless IPI.
--
Gleb.
Zhang, Yang Z wrote on 2013-03-15:
Quoted 55 lines
From: Yang Zhang <[email protected]>
The follwoing patches are adding the Posted Interrupt supporting to KVM:
The first patch enables the feature 'acknowledge interrupt on vmexit'.Since it is required by Posted interrupt, we need to enable it firstly.And the subsequent patches are adding the posted interrupt supporting:
Posted Interrupt allows APIC interrupts to inject into guest directly without any vmexit.- When delivering a interrupt to guest, if target vcpu is running, update Posted-interrupt requests bitmap and send a notification event to the vcpu. Then the vcpu will handle this interrupt automatically, without any software involvemnt.
- If target vcpu is not running or there already a notification event pending in the vcpu, do nothing. The interrupt will be handled by next vm entry
NOTE: We don't turn on the Posted Interrupt until the coalesced issue is solved.Changes from v5 to v6:
* Splitsync_pir_to_irrinto two functions one to query whether PIR is empty and the other to perform the sync.
* Add comments to explain howvmx_sync_pir_to_irr()work.
* Rebase on top of KVM upstream.Changes from v4 to v5:
* Add per cpu count for posted IPI handler.
* Dont' check irr when delivering interrupt. Since we can not get interrupt coalesced info with Posted Interrupt. So there is no need to check the irr. There is another patch will changed current interrupt coalesced logic. Before it, we will not turn on Posted Interrupt. * Clear outstanding notification bit after calllocal_irq_disable, but before check request. As Marcelo suggested, we can ensure the IPI not lost in this way * Remove the spinlock. Same as item 2, if not need to get coalesced info, then no need the lock.
* Rebase on top of KVM upstream.Yang Zhang (5):
KVM: VMX: Enable acknowledge interupt on vmexit
KVM: VMX: Register a new IPI for posted interrupt
KVM: VMX: Check the posted interrupt capability
KVM: VMX: Add the algorithm of deliver posted interrupt KVM : VMX: Use posted interrupt to deliver virtual interruptarch/x86/include/asm/entry_arch.h | 4 + arch/x86/include/asm/hardirq.h | 3 + arch/x86/include/asm/hw_irq.h | 1 + arch/x86/include/asm/irq_vectors.h | 5 + arch/x86/include/asm/kvm_host.h | 5 + arch/x86/include/asm/vmx.h | 4 + arch/x86/kernel/entry_64.S | 5 + arch/x86/kernel/irq.c | 22 ++++ arch/x86/kernel/irqinit.c | 4 + arch/x86/kvm/irq.c | 3 +- arch/x86/kvm/lapic.c | 29 ++++- arch/x86/kvm/lapic.h | 2 + arch/x86/kvm/svm.c | 30 +++++ arch/x86/kvm/vmx.c | 223
Quoted 3 lines
++++++++++++++++++++++++++++++++----
arch/x86/kvm/x86.c
| 8 +-virt/kvm/kvm_main.c| 1 + 16 files changed,
320 insertions(+), 29 deletions(-)
Are there any other comments with this patch?
For TMR issue, since it has nothing to do with APICv, if we really need to handle it later, then we may need a separate patch to fix it. But currently, we may focused on APICv only.
Best regards,
Yang
Quoted 59 lines · Yang Z
Zhang, Yang Z wrote on 2013-03-15:
Quoted 55 lines
From: Yang Zhang <[email protected]>
The follwoing patches are adding the Posted Interrupt supporting to KVM:
The first patch enables the feature 'acknowledge interrupt on vmexit'.Since it is required by Posted interrupt, we need to enable it firstly.And the subsequent patches are adding the posted interrupt supporting:
Posted Interrupt allows APIC interrupts to inject into guest directly without any vmexit.- When delivering a interrupt to guest, if target vcpu is running, update Posted-interrupt requests bitmap and send a notification event to the vcpu. Then the vcpu will handle this interrupt automatically, without any software involvemnt.
- If target vcpu is not running or there already a notification event pending in the vcpu, do nothing. The interrupt will be handled by next vm entry
NOTE: We don't turn on the Posted Interrupt until the coalesced issue is solved.Changes from v5 to v6:
* Splitsync_pir_to_irrinto two functions one to query whether PIR is empty and the other to perform the sync.
* Add comments to explain howvmx_sync_pir_to_irr()work.
* Rebase on top of KVM upstream.Changes from v4 to v5:
* Add per cpu count for posted IPI handler.
* Dont' check irr when delivering interrupt. Since we can not get interrupt coalesced info with Posted Interrupt. So there is no need to check the irr. There is another patch will changed current interrupt coalesced logic. Before it, we will not turn on Posted Interrupt. * Clear outstanding notification bit after calllocal_irq_disable, but before check request. As Marcelo suggested, we can ensure the IPI not lost in this way * Remove the spinlock. Same as item 2, if not need to get coalesced info, then no need the lock.
* Rebase on top of KVM upstream.Yang Zhang (5):
KVM: VMX: Enable acknowledge interupt on vmexit
KVM: VMX: Register a new IPI for posted interrupt
KVM: VMX: Check the posted interrupt capability
KVM: VMX: Add the algorithm of deliver posted interrupt KVM : VMX: Use posted interrupt to deliver virtual interruptarch/x86/include/asm/entry_arch.h | 4 + arch/x86/include/asm/hardirq.h | 3 + arch/x86/include/asm/hw_irq.h | 1 + arch/x86/include/asm/irq_vectors.h | 5 + arch/x86/include/asm/kvm_host.h | 5 + arch/x86/include/asm/vmx.h | 4 + arch/x86/kernel/entry_64.S | 5 + arch/x86/kernel/irq.c | 22 ++++ arch/x86/kernel/irqinit.c | 4 + arch/x86/kvm/irq.c | 3 +- arch/x86/kvm/lapic.c | 29 ++++- arch/x86/kvm/lapic.h | 2 + arch/x86/kvm/svm.c | 30 +++++ arch/x86/kvm/vmx.c | 223Quoted 3 lines
++++++++++++++++++++++++++++++++----
arch/x86/kvm/x86.c
| 8 +-virt/kvm/kvm_main.c| 1 + 16 files changed,
320 insertions(+), 29 deletions(-)
Quoted 2 lines
Are there any other comments with this patch?
Haven't reviewed it yet, will do ASAP. "Use eoi to track RTC interrupt delivery status" series is pre-request for this one.
Quoted 2 lines
For TMR issue, since it has nothing to do with APICv, if we really need to handle it later, then we may need a separate patch to fix it. But currently, we may focused on APICv only.
What do you mean by "TMR has nothing to do with APICv"?
--
Gleb.
Gleb Natapov wrote on 2013-03-18:
Quoted 62 lines · Yang Z
Quoted 49 lines
Zhang, Yang Z wrote on 2013-03-15:
Quoted 48 lines
From: Yang Zhang <[email protected]>
The follwoing patches are adding the Posted Interrupt supporting to KVM:
The first patch enables the feature 'acknowledge interrupt on vmexit'.Since it is required by Posted interrupt, we need to enable it firstly.And the subsequent patches are adding the posted interrupt supporting:
Posted Interrupt allows APIC interrupts to inject into guest directly without any vmexit.- When delivering a interrupt to guest, if target vcpu is running, update Posted-interrupt requests bitmap and send a notification event to the vcpu. Then the vcpu will handle this interrupt automatically, without any software involvemnt. - If target vcpu is not running or there already a notification event pending in the vcpu, do nothing. The interrupt will be handled by next vm entry
NOTE: We don't turn on the Posted Interrupt until the coalesced issue is solved.Changes from v5 to v6:
* Splitsync_pir_to_irrinto two functions one to query whether PIR is empty and the other to perform the sync.
* Add comments to explain howvmx_sync_pir_to_irr()work.
* Rebase on top of KVM upstream.Changes from v4 to v5:
* Add per cpu count for posted IPI handler.
* Dont' check irr when delivering interrupt. Since we can not get interrupt coalesced info with Posted Interrupt. So there is no need to check the irr. There is another patch will changed current interrupt coalesced logic. Before it, we will not turn on Posted Interrupt. * Clear outstanding notification bit after calllocal_irq_disable, but before check request. As Marcelo suggested, we can ensure the IPI not lost in this way * Remove the spinlock. Same as item 2, if not need to get coalesced info, then no need the lock.
* Rebase on top of KVM upstream.Yang Zhang (5):
KVM: VMX: Enable acknowledge interupt on vmexit
KVM: VMX: Register a new IPI for posted interrupt
KVM: VMX: Check the posted interrupt capability
KVM: VMX: Add the algorithm of deliver posted interrupt KVM : VMX: Use posted interrupt to deliver virtual interruptarch/x86/include/asm/entry_arch.h | 4 + arch/x86/include/asm/hardirq.h | 3 + arch/x86/include/asm/hw_irq.h | 1 + arch/x86/include/asm/irq_vectors.h | 5 + arch/x86/include/asm/kvm_host.h | 5 +
arch/x86/include/asm/vmx.hQuoted 11 lines
Quoted 9 lines
| 4 + arch/x86/kernel/entry_64.S | 5 + arch/x86/kernel/irq.c | 22 ++++ arch/x86/kernel/irqinit.c | 4 + arch/x86/kvm/irq.c | 3 +- arch/x86/kvm/lapic.c | 29 ++++-
arch/x86/kvm/lapic.h| 2 +arch/x86/kvm/svm.c
| 30 +++++arch/x86/kvm/vmx.c| 223
++++++++++++++++++++++++++++++++----arch/x86/kvm/x86.c
| 8 +-virt/kvm/kvm_main.c| 1 + 16 files changed,
320 insertions(+), 29 deletions(-)Are there any other comments with this patch?
Quoted 8 lines
Haven't reviewed it yet, will do ASAP. "Use eoi to track RTC interrupt delivery status" series is pre-request for this one.
Quoted 1 line
For TMR issue, since it has nothing to do with APICv, if we really need to handle
it later, then we may need a separate patch to fix it. But currently, we may focused on APICv only.
Quoted 1 line
What do you mean by "TMR has nothing to do with APICv"?
Just ignore it. I will send out the fixing with APICv patch.
Best regards,
Yang
Quoted 7 lines · Yang Z
Quoted 5 lines
Quoted 1 line
For TMR issue, since it has nothing to do with APICv, if we really need to handle
it later, then we may need a separate patch to fix it. But currently, we may focused on APICv only.
Quoted 1 line
What do you mean by "TMR has nothing to do with APICv"?
Just ignore it. I will send out the fixing with APICv patch.
Does this mean we cannot get away with updating TMR like we do now? Because if we can I prefer to not complicate the code further.
--
Gleb.
Gleb Natapov wrote on 2013-03-18:
Quoted 11 lines · Yang Z
Quoted 1 line
Quoted 1 line
Quoted 1 line
For TMR issue, since it has nothing to do with APICv, if we really need to
handle
Quoted 6 lines
Quoted 4 lines
it later, then we may need a separate patch to fix it. But currently, we may focused on APICv only.
Quoted 1 line
What do you mean by "TMR has nothing to do with APICv"?
Just ignore it. I will send out the fixing with APICv patch.
Does this mean we cannot get away with updating TMR like we do now? Because if we can I prefer to not complicate the code further.
No, we still need to update TMR but only in vcpu context.
Best regards,
Yang
Quoted 15 lines · Yang Zhang
From: Yang Zhang <[email protected]>
The follwoing patches are adding the Posted Interrupt supporting to KVM:
The first patch enables the feature 'acknowledge interrupt on vmexit'.Since it is required by Posted interrupt, we need to enable it firstly.And the subsequent patches are adding the posted interrupt supporting:
Posted Interrupt allows APIC interrupts to inject into guest directly without any vmexit.- When delivering a interrupt to guest, if target vcpu is running, update Posted-interrupt requests bitmap and send a notification event to the vcpu. Then the vcpu will handle this interrupt automatically, without any software involvemnt.
Quoted 6 lines
- If target vcpu is not running or there already a notification event pending in the vcpu, do nothing. The interrupt will be handled by next vm entry
NOTE: We don't turn on the Posted Interrupt until the coalesced issue is solved.
Looks good, but RTC issue should be resolved.