From 40fb276dec8fddead88803a5ffc9d42ae7b54010 Mon Sep 17 00:00:00 2001 From: Peter Xu Date: Thu, 18 Aug 2016 03:00:21 +0200 Subject: [PATCH 03/37] ioapic: clear remote irr bit for edge-triggered interrupts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RH-Author: Peter Xu Message-id: <1471489253-2811-3-git-send-email-peterx@redhat.com> Patchwork-id: 71987 O-Subject: [RHEL-7.3 qemu-kvm-rhev v2 02/34] ioapic: clear remote irr bit for edge-triggered interrupts Bugzilla: 1358653 RH-Acked-by: Marcel Apfelbaum RH-Acked-by: Paolo Bonzini RH-Acked-by: Radim Krcmar This is to better emulate IOAPIC version 0x1X hardware. Linux kernel leveraged this "feature" to do explicit EOI since EOI register is still not introduced at that time. This will also fix the issue that level triggered interrupts failed to work when IR enabled (tested with Linux kernel version 4.5). Reviewed-by: Radim Krčmář Signed-off-by: Peter Xu Message-Id: <1462875682-1349-3-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini (cherry picked from commit ed1263c363c970a7ad5226b8f41dbbf0c92c1e17) Signed-off-by: Peter Xu Signed-off-by: Miroslav Rezanina --- hw/intc/ioapic.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c index ef9421d..310649d 100644 --- a/hw/intc/ioapic.c +++ b/hw/intc/ioapic.c @@ -254,6 +254,34 @@ ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size) return val; } +/* + * This is to satisfy the hack in Linux kernel. One hack of it is to + * simulate clearing the Remote IRR bit of IOAPIC entry using the + * following: + * + * "For IO-APIC's with EOI register, we use that to do an explicit EOI. + * Otherwise, we simulate the EOI message manually by changing the trigger + * mode to edge and then back to level, with RTE being masked during + * this." + * + * (See linux kernel __eoi_ioapic_pin() comment in commit c0205701) + * + * This is based on the assumption that, Remote IRR bit will be + * cleared by IOAPIC hardware when configured as edge-triggered + * interrupts. + * + * Without this, level-triggered interrupts in IR mode might fail to + * work correctly. + */ +static inline void +ioapic_fix_edge_remote_irr(uint64_t *entry) +{ + if (!(*entry & IOAPIC_LVT_TRIGGER_MODE)) { + /* Edge-triggered interrupts, make sure remote IRR is zero */ + *entry &= ~((uint64_t)IOAPIC_LVT_REMOTE_IRR); + } +} + static void ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, unsigned int size) @@ -291,6 +319,7 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val, /* restore RO bits */ s->ioredtbl[index] &= IOAPIC_RW_BITS; s->ioredtbl[index] |= ro_bits; + ioapic_fix_edge_remote_irr(&s->ioredtbl[index]); ioapic_service(s); } } -- 1.8.3.1