From f15cc7d6de078bff102e8c9693db7d5e99275510 Mon Sep 17 00:00:00 2001 From: "Yan, Like" Date: Fri, 4 Jan 2019 14:52:02 +0800 Subject: [PATCH] hv: set/clear TMR bit like hardware behave Current ACRN implementation update TMR bits one time only when related RTE fields changed, which is not acting like actual hardware. From SDM vol3 10.8.4: "Upon acceptance of an interrupt into the IRR, the corresponding TMR bit is cleared for edge-triggered interrupts and set for leveltriggered interrupts." This commit change the ACRN implementation to set/clear corresponding TMR bit when inject intr to vlapic. Tracked-On: #2343 Signed-off-by: Yan, Like Acked-by: Eddie Dong --- hypervisor/arch/x86/guest/vlapic.c | 84 ++++++++++------------ hypervisor/include/arch/x86/guest/vlapic.h | 3 - 2 files changed, 36 insertions(+), 51 deletions(-) diff --git a/hypervisor/arch/x86/guest/vlapic.c b/hypervisor/arch/x86/guest/vlapic.c index 3bbce497e..7d6430744 100644 --- a/hypervisor/arch/x86/guest/vlapic.c +++ b/hypervisor/arch/x86/guest/vlapic.c @@ -460,6 +460,36 @@ vlapic_esr_write_handler(struct acrn_vlapic *vlapic) vlapic->esr_pending = 0U; } +static void +vlapic_set_tmr(struct acrn_vlapic *vlapic, uint32_t vector, bool level) +{ + struct lapic_regs *lapic; + struct lapic_reg *tmrptr; + + lapic = &(vlapic->apic_page); + tmrptr = &lapic->tmr[0]; + if (level) { + bitmap32_set_lock((uint16_t)(vector & 0x1fU), &tmrptr[vector >> 5U].v); + } else { + bitmap32_clear_lock((uint16_t)(vector & 0x1fU), &tmrptr[vector >> 5U].v); + } +} + +static void +vlapic_reset_tmr(struct acrn_vlapic *vlapic) +{ + int16_t i; + struct lapic_regs *lapic; + + dev_dbg(ACRN_DBG_LAPIC, + "vlapic resetting all vectors to edge-triggered"); + + lapic = &(vlapic->apic_page); + for (i = 0; i < 8; i++) { + lapic->tmr[i].v = 0U; + } +} + /* * Returns 1 if the vcpu needs to be notified of the interrupt and 0 otherwise. * @pre vector >= 16 @@ -468,8 +498,7 @@ static bool vlapic_accept_intr(struct acrn_vlapic *vlapic, uint32_t vector, bool level) { struct lapic_regs *lapic; - struct lapic_reg *irrptr, *tmrptr; - uint32_t mask; + struct lapic_reg *irrptr; uint32_t idx; int32_t pending_intr; bool ret = true; @@ -483,6 +512,9 @@ vlapic_accept_intr(struct acrn_vlapic *vlapic, uint32_t vector, bool level) ret = false; } else if (is_apicv_intr_delivery_supported()) { pending_intr = apicv_set_intr_ready(vlapic, vector); + + vlapic_set_tmr(vlapic, vector, level); + if ((pending_intr != 0) && (is_apicv_posted_intr_supported()) && (get_cpu_id() != vlapic->vcpu->pcpu_id)) { /* * Send interrupt to vCPU via posted interrupt way: @@ -502,24 +534,14 @@ vlapic_accept_intr(struct acrn_vlapic *vlapic, uint32_t vector, bool level) } } else { idx = vector >> 5U; - mask = 1U << (vector & 0x1fU); irrptr = &lapic->irr[0]; /* If the interrupt is set, don't try to do it again */ if (bitmap32_test_and_set_lock((uint16_t)(vector & 0x1fU), &irrptr[idx].v)) { ret = false; } else { - /* - * Verify that the trigger-mode of the interrupt matches with - * the vlapic TMR registers. - */ - tmrptr = &lapic->tmr[0]; - if ((tmrptr[idx].v & mask) != (level ? mask : 0U)) { - dev_dbg(ACRN_DBG_LAPIC, "vlapic TMR[%u] is 0x%08x but interrupt is %s-triggered", - idx, tmrptr[idx].v, level ? "level" : "edge"); - } - - vlapic_dump_irr(vlapic, "vlapic_accept_intr"); + /* set tmr if corresponding irr bit changes from 0 to 1 */ + vlapic_set_tmr(vlapic, vector, level); } } @@ -1844,24 +1866,6 @@ vlapic_enabled(const struct acrn_vlapic *vlapic) return ret; } -static void -vlapic_set_tmr(struct acrn_vlapic *vlapic, uint32_t vector, bool level) -{ - struct lapic_regs *lapic; - struct lapic_reg *tmrptr; - uint32_t mask, idx; - - lapic = &(vlapic->apic_page); - tmrptr = &lapic->tmr[0]; - idx = vector >> 5U; - mask = 1U << (vector & 0x1fU); - if (level) { - tmrptr[idx].v |= mask; - } else { - tmrptr[idx].v &= ~mask; - } -} - /* * APICv batch set tmr will try to set multi vec at the same time * to avoid unnecessary VMCS read/update. @@ -1874,22 +1878,6 @@ vlapic_apicv_batch_set_tmr(struct acrn_vlapic *vlapic) } } -void -vlapic_reset_tmr(struct acrn_vlapic *vlapic) -{ - struct acrn_vcpu *vcpu = vlapic->vcpu; - uint32_t vector; - - dev_dbg(ACRN_DBG_LAPIC, - "vlapic resetting all vectors to edge-triggered"); - - for (vector = 0U; vector <= 255U; vector++) { - vlapic_set_tmr(vlapic, vector, false); - } - - vcpu_make_request(vcpu, ACRN_REQUEST_TMR_UPDATE); -} - void vlapic_set_tmr_one_vec(struct acrn_vlapic *vlapic, uint32_t delmode, uint32_t vector, bool level) diff --git a/hypervisor/include/arch/x86/guest/vlapic.h b/hypervisor/include/arch/x86/guest/vlapic.h index 14b73b700..675c91e31 100644 --- a/hypervisor/include/arch/x86/guest/vlapic.h +++ b/hypervisor/include/arch/x86/guest/vlapic.h @@ -227,9 +227,6 @@ int32_t vlapic_intr_msi(struct acrn_vm *vm, uint64_t addr, uint64_t msg); void vlapic_deliver_intr(struct acrn_vm *vm, bool level, uint32_t dest, bool phys, uint32_t delmode, uint32_t vec, bool rh); -/* Reset the trigger-mode bits for all vectors to be edge-triggered */ -void vlapic_reset_tmr(struct acrn_vlapic *vlapic); - /* * Set the trigger-mode bit associated with 'vector' to level-triggered if * the (dest,phys,delmode) tuple resolves to an interrupt being delivered to