aboutsummaryrefslogtreecommitdiff
path: root/hw/intc
diff options
context:
space:
mode:
authorPeter Xu <peterx@redhat.com>2016-08-01 21:59:19 +0800
committerPaolo Bonzini <pbonzini@redhat.com>2016-08-03 18:44:57 +0200
commit20fd4b7b6d9282fe0cb83601f1821f31bd257458 (patch)
treefddd31b6f2361778022e9471dae63c27a8b9f0f9 /hw/intc
parentf99b86b94987561580a94838766458e1c7b8685d (diff)
x86: ioapic: add support for explicit EOI
Some old Linux kernels (upstream before v4.0), or any released RHEL kernels has problem in sending APIC EOI when IR is enabled. Meanwhile, many of them only support explicit EOI for IOAPIC, which is only introduced in IOAPIC version 0x20. This patch provide a way to boost QEMU IOAPIC to version 0x20, in order for QEMU to correctly receive EOI messages. Without boosting IOAPIC version to 0x20, kernels before commit d32932d ("x86/irq: Convert IOAPIC to use hierarchical irqdomain interfaces") will have trouble enabling both IR and level-triggered interrupt devices (like e1000). To upgrade IOAPIC to version 0x20, we need to specify: -global ioapic.version=0x20 To be compatible with old systems, 0x11 will still be the default IOAPIC version. Here 0x11 and 0x20 are the only versions to be supported. One thing to mention: this patch only applies to emulated IOAPIC. It does not affect kernel IOAPIC behavior. Signed-off-by: Peter Xu <peterx@redhat.com> Message-Id: <1470059959-372-1-git-send-email-peterx@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/intc')
-rw-r--r--hw/intc/ioapic.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/hw/intc/ioapic.c b/hw/intc/ioapic.c
index a00d88210a..31791b0986 100644
--- a/hw/intc/ioapic.c
+++ b/hw/intc/ioapic.c
@@ -21,6 +21,7 @@
*/
#include "qemu/osdep.h"
+#include "qemu/error-report.h"
#include "monitor/monitor.h"
#include "hw/hw.h"
#include "hw/i386/pc.h"
@@ -269,7 +270,7 @@ ioapic_mem_read(void *opaque, hwaddr addr, unsigned int size)
val = s->id << IOAPIC_ID_SHIFT;
break;
case IOAPIC_REG_VER:
- val = IOAPIC_VERSION |
+ val = s->version |
((IOAPIC_NUM_PINS - 1) << IOAPIC_VER_ENTRIES_SHIFT);
break;
default:
@@ -358,6 +359,13 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
}
}
break;
+ case IOAPIC_EOI:
+ /* Explicit EOI is only supported for IOAPIC version 0x20 */
+ if (size != 4 || s->version != 0x20) {
+ break;
+ }
+ ioapic_eoi_broadcast(val);
+ break;
}
ioapic_update_kvm_routes(s);
@@ -391,6 +399,12 @@ static void ioapic_realize(DeviceState *dev, Error **errp)
{
IOAPICCommonState *s = IOAPIC_COMMON(dev);
+ if (s->version != 0x11 && s->version != 0x20) {
+ error_report("IOAPIC only supports version 0x11 or 0x20 "
+ "(default: 0x11).");
+ exit(1);
+ }
+
memory_region_init_io(&s->io_memory, OBJECT(s), &ioapic_io_ops, s,
"ioapic", 0x1000);
@@ -401,6 +415,11 @@ static void ioapic_realize(DeviceState *dev, Error **errp)
qemu_add_machine_init_done_notifier(&s->machine_done);
}
+static Property ioapic_properties[] = {
+ DEFINE_PROP_UINT8("version", IOAPICCommonState, version, 0x11),
+ DEFINE_PROP_END_OF_LIST(),
+};
+
static void ioapic_class_init(ObjectClass *klass, void *data)
{
IOAPICCommonClass *k = IOAPIC_COMMON_CLASS(klass);
@@ -408,6 +427,7 @@ static void ioapic_class_init(ObjectClass *klass, void *data)
k->realize = ioapic_realize;
dc->reset = ioapic_reset_common;
+ dc->props = ioapic_properties;
}
static const TypeInfo ioapic_info = {