[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [RFT][PATCH 08/15] x86: Refactor RTC IRQ coalescing workaro
From: |
Jan Kiszka |
Subject: |
[Qemu-devel] [RFT][PATCH 08/15] x86: Refactor RTC IRQ coalescing workaround |
Date: |
Mon, 24 May 2010 22:13:41 +0200 |
From: Jan Kiszka <address@hidden>
Make use of the new feedback IRQ handlers and propagate coalesced
deliveries via handler return code from the sink to the source. As a
by-product, this also adds coalescing support to the PIC.
Signed-off-by: Jan Kiszka <address@hidden>
---
hw/apic.c | 61 ++++++++++++++++++++++++++---------------------------
hw/apic.h | 10 ++------
hw/i8259.c | 20 +++++++++++++++--
hw/ioapic.c | 34 ++++++++++++++++++-----------
hw/mc146818rtc.c | 22 ++++++++-----------
hw/pc.c | 17 ++++++++++----
hw/pc.h | 2 +-
hw/pc_piix.c | 2 +-
8 files changed, 94 insertions(+), 74 deletions(-)
diff --git a/hw/apic.c b/hw/apic.c
index 9029dad..641825c 100644
--- a/hw/apic.c
+++ b/hw/apic.c
@@ -108,10 +108,8 @@ typedef struct APICState {
static int apic_io_memory;
static APICState *local_apics[MAX_APICS + 1];
static int last_apic_idx = 0;
-static int apic_irq_delivered;
-
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode);
+static int apic_set_irq(APICState *s, int vector_num, int trigger_mode);
static void apic_update_irq(APICState *s);
static void apic_get_delivery_bitmask(uint32_t *deliver_bitmask,
uint8_t dest, uint8_t dest_mode);
@@ -222,12 +220,12 @@ void apic_deliver_pic_intr(CPUState *env, int level)
}\
}
-static void apic_bus_deliver(const uint32_t *deliver_bitmask,
- uint8_t delivery_mode,
- uint8_t vector_num, uint8_t polarity,
- uint8_t trigger_mode)
+static int apic_bus_deliver(const uint32_t *deliver_bitmask,
+ uint8_t delivery_mode, uint8_t vector_num,
+ uint8_t polarity, uint8_t trigger_mode)
{
APICState *apic_iter;
+ int ret;
switch (delivery_mode) {
case APIC_DM_LOWPRI:
@@ -244,11 +242,12 @@ static void apic_bus_deliver(const uint32_t
*deliver_bitmask,
if (d >= 0) {
apic_iter = local_apics[d];
if (apic_iter) {
- apic_set_irq(apic_iter, vector_num, trigger_mode);
+ return apic_set_irq(apic_iter, vector_num,
+ trigger_mode);
}
}
}
- return;
+ return QEMU_IRQ_MASKED;
case APIC_DM_FIXED:
break;
@@ -256,40 +255,48 @@ static void apic_bus_deliver(const uint32_t
*deliver_bitmask,
case APIC_DM_SMI:
foreach_apic(apic_iter, deliver_bitmask,
cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_SMI) );
- return;
+ return QEMU_IRQ_DELIVERED;
case APIC_DM_NMI:
foreach_apic(apic_iter, deliver_bitmask,
cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_NMI) );
- return;
+ return QEMU_IRQ_DELIVERED;
case APIC_DM_INIT:
/* normal INIT IPI sent to processors */
foreach_apic(apic_iter, deliver_bitmask,
cpu_interrupt(apic_iter->cpu_env, CPU_INTERRUPT_INIT)
);
- return;
+ return QEMU_IRQ_DELIVERED;
case APIC_DM_EXTINT:
/* handled in I/O APIC code */
break;
default:
- return;
+ return QEMU_IRQ_MASKED;
}
+ ret = QEMU_IRQ_MASKED;
foreach_apic(apic_iter, deliver_bitmask,
- apic_set_irq(apic_iter, vector_num, trigger_mode) );
+ if (ret == QEMU_IRQ_MASKED)
+ ret = QEMU_IRQ_COALESCED;
+ if (apic_set_irq(apic_iter, vector_num,
+ trigger_mode) == QEMU_IRQ_DELIVERED) {
+ ret = QEMU_IRQ_DELIVERED;
+ }
+ );
+ return ret;
}
-void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
- uint8_t delivery_mode, uint8_t vector_num,
- uint8_t polarity, uint8_t trigger_mode)
+int apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
+ uint8_t delivery_mode, uint8_t vector_num,
+ uint8_t polarity, uint8_t trigger_mode)
{
uint32_t deliver_bitmask[MAX_APIC_WORDS];
apic_get_delivery_bitmask(deliver_bitmask, dest, dest_mode);
- apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num, polarity,
- trigger_mode);
+ return apic_bus_deliver(deliver_bitmask, delivery_mode, vector_num,
+ polarity, trigger_mode);
}
void cpu_set_apic_base(CPUState *env, uint64_t val)
@@ -384,19 +391,10 @@ static void apic_update_irq(APICState *s)
cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
}
-void apic_reset_irq_delivered(void)
-{
- apic_irq_delivered = 0;
-}
-
-int apic_get_irq_delivered(void)
-{
- return apic_irq_delivered;
-}
-
-static void apic_set_irq(APICState *s, int vector_num, int trigger_mode)
+static int apic_set_irq(APICState *s, int vector_num, int trigger_mode)
{
- apic_irq_delivered += !get_bit(s->irr, vector_num);
+ int ret = get_bit(s->irr, vector_num) ? QEMU_IRQ_COALESCED
+ : QEMU_IRQ_DELIVERED;
set_bit(s->irr, vector_num);
if (trigger_mode)
@@ -404,6 +402,7 @@ static void apic_set_irq(APICState *s, int vector_num, int
trigger_mode)
else
reset_bit(s->tmr, vector_num);
apic_update_irq(s);
+ return ret;
}
static void apic_eoi(APICState *s)
diff --git a/hw/apic.h b/hw/apic.h
index 132fcab..738d98a 100644
--- a/hw/apic.h
+++ b/hw/apic.h
@@ -2,18 +2,14 @@
#define APIC_H
typedef struct IOAPICState IOAPICState;
-void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
- uint8_t delivery_mode,
- uint8_t vector_num, uint8_t polarity,
- uint8_t trigger_mode);
+int apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
+ uint8_t delivery_mode, uint8_t vector_num,
+ uint8_t polarity, uint8_t trigger_mode);
int apic_init(CPUState *env);
int apic_accept_pic_intr(CPUState *env);
void apic_deliver_pic_intr(CPUState *env, int level);
int apic_get_interrupt(CPUState *env);
qemu_irq *ioapic_init(void);
-void ioapic_set_irq(void *opaque, int vector, int level);
-void apic_reset_irq_delivered(void);
-int apic_get_irq_delivered(void);
int cpu_is_bsp(CPUState *env);
diff --git a/hw/i8259.c b/hw/i8259.c
index ea48e0e..c05adf2 100644
--- a/hw/i8259.c
+++ b/hw/i8259.c
@@ -179,9 +179,12 @@ void pic_update_irq(PicState2 *s)
int64_t irq_time[16];
#endif
-static void i8259_set_irq(void *opaque, int irq, int level)
+static int i8259_set_irq(void *opaque, int irq, int level)
{
PicState2 *s = opaque;
+ PicState *pic;
+ int ret = QEMU_IRQ_DELIVERED;
+ int mask;
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
if (level != irq_level[irq]) {
@@ -200,8 +203,19 @@ static void i8259_set_irq(void *opaque, int irq, int level)
irq_time[irq] = qemu_get_clock(vm_clock);
}
#endif
- pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+ pic = &s->pics[irq >> 3];
+ irq &= 7;
+ mask = 1 << irq;
+ if (level) {
+ if (pic->imr & mask) {
+ ret = QEMU_IRQ_MASKED;
+ } else if (pic->irr & mask) {
+ ret = QEMU_IRQ_COALESCED;
+ }
+ }
+ pic_set_irq1(pic, irq, level);
pic_update_irq(s);
+ return ret;
}
/* acknowledge interrupt 'irq' */
@@ -536,5 +550,5 @@ qemu_irq *i8259_init(qemu_irq parent_irq)
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
isa_pic = s;
- return qemu_allocate_irqs(i8259_set_irq, s, 16);
+ return qemu_allocate_feedback_irqs(i8259_set_irq, s, 16);
}
diff --git a/hw/ioapic.c b/hw/ioapic.c
index 7ad8018..179fe49 100644
--- a/hw/ioapic.c
+++ b/hw/ioapic.c
@@ -51,7 +51,7 @@ struct IOAPICState {
uint64_t ioredtbl[IOAPIC_NUM_PINS];
};
-static void ioapic_service(IOAPICState *s)
+static int ioapic_service(IOAPICState *s)
{
uint8_t i;
uint8_t trig_mode;
@@ -62,12 +62,16 @@ static void ioapic_service(IOAPICState *s)
uint8_t dest;
uint8_t dest_mode;
uint8_t polarity;
+ int ret = QEMU_IRQ_MASKED;
for (i = 0; i < IOAPIC_NUM_PINS; i++) {
mask = 1 << i;
if (s->irr & mask) {
entry = s->ioredtbl[i];
if (!(entry & IOAPIC_LVT_MASKED)) {
+ if (ret == QEMU_IRQ_MASKED) {
+ ret = QEMU_IRQ_COALESCED;
+ }
trig_mode = ((entry >> 15) & 1);
dest = entry >> 56;
dest_mode = (entry >> 11) & 1;
@@ -80,33 +84,39 @@ static void ioapic_service(IOAPICState *s)
else
vector = entry & 0xff;
- apic_deliver_irq(dest, dest_mode, delivery_mode,
- vector, polarity, trig_mode);
+ if (apic_deliver_irq(dest, dest_mode,
+ delivery_mode, vector, polarity,
+ trig_mode) == QEMU_IRQ_DELIVERED) {
+ ret = QEMU_IRQ_DELIVERED;
+ }
}
}
}
+ return ret;
}
-void ioapic_set_irq(void *opaque, int vector, int level)
+static int ioapic_set_irq(void *opaque, int vector, int level)
{
+ int mapped_vector = vector;
IOAPICState *s = opaque;
+ int ret = QEMU_IRQ_MASKED;
/* ISA IRQs map to GSI 1-1 except for IRQ0 which maps
* to GSI 2. GSI maps to ioapic 1-1. This is not
* the cleanest way of doing it but it should work. */
if (vector == 0)
- vector = 2;
+ mapped_vector = 2;
if (vector >= 0 && vector < IOAPIC_NUM_PINS) {
- uint32_t mask = 1 << vector;
- uint64_t entry = s->ioredtbl[vector];
+ uint32_t mask = 1 << mapped_vector;
+ uint64_t entry = s->ioredtbl[mapped_vector];
if ((entry >> 15) & 1) {
/* level triggered */
if (level) {
s->irr |= mask;
- ioapic_service(s);
+ ret = ioapic_service(s);
} else {
s->irr &= ~mask;
}
@@ -114,10 +124,11 @@ void ioapic_set_irq(void *opaque, int vector, int level)
/* edge triggered */
if (level) {
s->irr |= mask;
- ioapic_service(s);
+ ret = ioapic_service(s);
}
}
}
+ return ret;
}
static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
@@ -230,7 +241,6 @@ static CPUWriteMemoryFunc * const ioapic_mem_write[3] = {
qemu_irq *ioapic_init(void)
{
IOAPICState *s;
- qemu_irq *irq;
int io_memory;
s = qemu_mallocz(sizeof(IOAPICState));
@@ -242,7 +252,5 @@ qemu_irq *ioapic_init(void)
vmstate_register(0, &vmstate_ioapic, s);
qemu_register_reset(ioapic_reset, s);
- irq = qemu_allocate_irqs(ioapic_set_irq, s, IOAPIC_NUM_PINS);
-
- return irq;
+ return qemu_allocate_feedback_irqs(ioapic_set_irq, s, IOAPIC_NUM_PINS);
}
diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
index 571c593..697f723 100644
--- a/hw/mc146818rtc.c
+++ b/hw/mc146818rtc.c
@@ -25,7 +25,6 @@
#include "qemu-timer.h"
#include "sysemu.h"
#include "pc.h"
-#include "apic.h"
#include "isa.h"
#include "hpet_emul.h"
#include "mc146818rtc.h"
@@ -94,7 +93,7 @@ typedef struct RTCState {
QEMUTimer *second_timer2;
} RTCState;
-static void rtc_irq_raise(qemu_irq irq)
+static int rtc_irq_raise(qemu_irq irq)
{
/* When HPET is operating in legacy mode, RTC interrupts are disabled
* We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
@@ -102,9 +101,11 @@ static void rtc_irq_raise(qemu_irq irq)
* be lowered in any case
*/
#if defined TARGET_I386
- if (!hpet_in_legacy_mode())
+ if (hpet_in_legacy_mode()) {
+ return QEMU_IRQ_MASKED;
+ }
#endif
- qemu_irq_raise(irq);
+ return qemu_irq_raise(irq);
}
static void rtc_set_time(RTCState *s);
@@ -129,10 +130,8 @@ static void rtc_coalesced_timer(void *opaque)
RTCState *s = opaque;
if (s->irq_coalesced != 0) {
- apic_reset_irq_delivered();
s->cmos_data[RTC_REG_C] |= 0xc0;
- rtc_irq_raise(s->irq);
- if (apic_get_irq_delivered()) {
+ if (rtc_irq_raise(s->irq) != QEMU_IRQ_COALESCED) {
s->irq_coalesced--;
}
}
@@ -193,9 +192,7 @@ static void rtc_periodic_timer(void *opaque)
if(rtc_td_hack) {
if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT)
s->irq_reinject_on_ack_count = 0;
- apic_reset_irq_delivered();
- rtc_irq_raise(s->irq);
- if (!apic_get_irq_delivered()) {
+ if (rtc_irq_raise(s->irq) == QEMU_IRQ_COALESCED) {
s->irq_coalesced++;
rtc_coalesced_timer_update(s);
}
@@ -475,10 +472,9 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t
addr)
if(s->irq_coalesced &&
s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT) {
s->irq_reinject_on_ack_count++;
- apic_reset_irq_delivered();
- qemu_irq_raise(s->irq);
- if (apic_get_irq_delivered())
+ if (qemu_irq_raise(s->irq) != QEMU_IRQ_COALESCED) {
s->irq_coalesced--;
+ }
break;
}
#endif
diff --git a/hw/pc.c b/hw/pc.c
index 631b0ae..ec6c32b 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -67,15 +67,22 @@ struct e820_table {
static struct e820_table e820_table;
-void isa_irq_handler(void *opaque, int n, int level)
+int isa_irq_handler(void *opaque, int n, int level)
{
- IsaIrqState *isa = (IsaIrqState *)opaque;
+ IsaIrqState *isa = opaque;
+ int ret = QEMU_IRQ_MASKED;
+ int ioapic_ret;
if (n < 16) {
- qemu_set_irq(isa->i8259[n], level);
+ ret = qemu_set_irq(isa->i8259[n], level);
}
- if (isa->ioapic)
- qemu_set_irq(isa->ioapic[n], level);
+ if (isa->ioapic) {
+ ioapic_ret = qemu_set_irq(isa->ioapic[n], level);
+ if (ioapic_ret == QEMU_IRQ_DELIVERED || ret == QEMU_IRQ_MASKED) {
+ ret = ioapic_ret;
+ }
+ }
+ return ret;
};
static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
diff --git a/hw/pc.h b/hw/pc.h
index 73cccef..015412f 100644
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -44,7 +44,7 @@ typedef struct isa_irq_state {
qemu_irq *ioapic;
} IsaIrqState;
-void isa_irq_handler(void *opaque, int n, int level);
+int isa_irq_handler(void *opaque, int n, int level);
/* i8254.c */
diff --git a/hw/pc_piix.c b/hw/pc_piix.c
index 70f563a..648b607 100644
--- a/hw/pc_piix.c
+++ b/hw/pc_piix.c
@@ -78,7 +78,7 @@ static void pc_init1(ram_addr_t ram_size,
if (pci_enabled) {
isa_irq_state->ioapic = ioapic_init();
}
- isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
+ isa_irq = qemu_allocate_feedback_irqs(isa_irq_handler, isa_irq_state, 24);
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, &piix3_devfn, isa_irq, ram_size);
--
1.6.0.2
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, (continued)
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, Gleb Natapov, 2010/05/31
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, Blue Swirl, 2010/05/30
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, Jan Kiszka, 2010/05/29
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, Blue Swirl, 2010/05/29
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, Jan Kiszka, 2010/05/29
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, Blue Swirl, 2010/05/29
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, Jan Kiszka, 2010/05/29
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, Gleb Natapov, 2010/05/27
- Re: [Qemu-devel] Re: [RFT][PATCH 07/15] qemu_irq: Add IRQ handlers with delivery feedback, Blue Swirl, 2010/05/26
[Qemu-devel] [RFT][PATCH 11/15] hpet: Add support for level-triggered interrupts, Jan Kiszka, 2010/05/24
[Qemu-devel] [RFT][PATCH 08/15] x86: Refactor RTC IRQ coalescing workaround,
Jan Kiszka <=
[Qemu-devel] [RFT][PATCH 12/15] vmstate: Add VMSTATE_STRUCT_VARRAY_UINT8, Jan Kiszka, 2010/05/24
[Qemu-devel] [RFT][PATCH 14/15] hpet: Add MSI support, Jan Kiszka, 2010/05/24
Re: [Qemu-devel] [RFT][PATCH 00/15] HPET cleanups, fixes, enhancements, Anthony Liguori, 2010/05/24