@@ -364,6 +364,23 @@ ioapic_fix_edge_remote_irr(uint64_t *entry)
}
}
+static inline void
+ioapic_fix_level_trigger_unsupported(uint64_t *entry)
+{
+ if ((*entry & IOAPIC_LVT_TRIGGER_MODE) !=
+ IOAPIC_TRIGGER_EDGE << IOAPIC_LVT_TRIGGER_MODE_SHIFT) {
+ /*
+ * ignore a request for level trigger because
+ * level trigger requires eoi intercept to re-inject
+ * interrupt when the level is still active.
+ */
+ warn_report_once("attempting to set level-trigger mode "
+ "while eoi intercept isn't supported");
+ *entry &= ~IOAPIC_LVT_TRIGGER_MODE;
+ *entry |= IOAPIC_TRIGGER_EDGE << IOAPIC_LVT_TRIGGER_MODE_SHIFT;
+ }
+}
+
static void
ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
unsigned int size)
@@ -404,6 +421,9 @@ ioapic_mem_write(void *opaque, hwaddr addr, uint64_t val,
s->ioredtbl[index] &= IOAPIC_RW_BITS;
s->ioredtbl[index] |= ro_bits;
s->irq_eoi[index] = 0;
+ if (s->level_trigger_unsupported) {
+ ioapic_fix_level_trigger_unsupported(&s->ioredtbl[index]);
+ }
ioapic_fix_edge_remote_irr(&s->ioredtbl[index]);
ioapic_service(s);
}
@@ -150,6 +150,32 @@ static int ioapic_dispatch_post_load(void *opaque, int version_id)
return 0;
}
+static bool ioapic_common_get_level_trigger_unsupported(Object *obj,
+ Error **errp)
+{
+ IOAPICCommonState *s = IOAPIC_COMMON(obj);
+ return s->level_trigger_unsupported;
+}
+
+static void ioapic_common_set_level_trigger_unsupported(Object *obj, bool value,
+ Error **errp)
+{
+ DeviceState *dev = DEVICE(obj);
+ IOAPICCommonState *s = IOAPIC_COMMON(obj);
+ /* only disabling before realize is allowed */
+ assert(!dev->realized);
+ assert(!s->level_trigger_unsupported);
+ s->level_trigger_unsupported = value;
+}
+
+static void ioapic_common_init(Object *obj)
+{
+ object_property_add_bool(obj, "level_trigger_unsupported",
+ ioapic_common_get_level_trigger_unsupported,
+ ioapic_common_set_level_trigger_unsupported);
+
+}
+
static void ioapic_common_realize(DeviceState *dev, Error **errp)
{
IOAPICCommonState *s = IOAPIC_COMMON(dev);
@@ -207,6 +233,7 @@ static const TypeInfo ioapic_common_type = {
.name = TYPE_IOAPIC_COMMON,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IOAPICCommonState),
+ .instance_init = ioapic_common_init,
.class_size = sizeof(IOAPICCommonClass),
.class_init = ioapic_common_class_init,
.abstract = true,
@@ -103,6 +103,7 @@ struct IOAPICCommonState {
uint32_t irr;
uint64_t ioredtbl[IOAPIC_NUM_PINS];
Notifier machine_done;
+ bool level_trigger_unsupported;
uint8_t version;
uint64_t irq_count[IOAPIC_NUM_PINS];
int irq_level[IOAPIC_NUM_PINS];