diff options
| -rw-r--r-- | arch/x86/kernel/apic/x2apic_savic.c | 31 |
1 files changed, 30 insertions, 1 deletions
diff --git a/arch/x86/kernel/apic/x2apic_savic.c b/arch/x86/kernel/apic/x2apic_savic.c index b6d6e7a69c89..d76faeaced83 100644 --- a/arch/x86/kernel/apic/x2apic_savic.c +++ b/arch/x86/kernel/apic/x2apic_savic.c @@ -301,6 +301,35 @@ static void savic_update_vector(unsigned int cpu, unsigned int vector, bool set) update_vector(cpu, SAVIC_ALLOWED_IRR, vector, set); } +static void savic_eoi(void) +{ + unsigned int cpu; + int vec; + + cpu = raw_smp_processor_id(); + vec = apic_find_highest_vector(get_reg_bitmap(cpu, APIC_ISR)); + if (WARN_ONCE(vec == -1, "EOI write while no active interrupt in APIC_ISR")) + return; + + /* Is level-triggered interrupt? */ + if (apic_test_vector(vec, get_reg_bitmap(cpu, APIC_TMR))) { + update_vector(cpu, APIC_ISR, vec, false); + /* + * Propagate the EOI write to the hypervisor for level-triggered + * interrupts. Return to the guest from GHCB protocol event takes + * care of re-evaluating interrupt state. + */ + savic_ghcb_msr_write(APIC_EOI, 0); + } else { + /* + * Hardware clears APIC_ISR and re-evaluates the interrupt state + * to determine if there is any pending interrupt which can be + * delivered to CPU. + */ + native_apic_msr_eoi(); + } +} + static void savic_setup(void) { void *ap = this_cpu_ptr(savic_page); @@ -380,7 +409,7 @@ static struct apic apic_x2apic_savic __ro_after_init = { .read = savic_read, .write = savic_write, - .eoi = native_apic_msr_eoi, + .eoi = savic_eoi, .icr_read = native_x2apic_icr_read, .icr_write = savic_icr_write, |
