[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] Re: [PATCH 10/16] x86: Refactor RTC IRQ coalescing workarou
From: |
Blue Swirl |
Subject: |
[Qemu-devel] Re: [PATCH 10/16] x86: Refactor RTC IRQ coalescing workaround |
Date: |
Sun, 6 Jun 2010 08:49:02 +0000 |
On Sun, Jun 6, 2010 at 8:10 AM, Jan Kiszka <address@hidden> wrote:
> From: Jan Kiszka <address@hidden>
>
> Make use of the new IRQ message and report delivery results from the
> sink to the source. As a by-product, this also adds de-coalescing
> support to the PIC.
>
> Signed-off-by: Jan Kiszka <address@hidden>
> ---
> hw/apic.c | 64 +++++++++++++++++++----------------------
> hw/apic.h | 9 ++----
> hw/i8259.c | 16 ++++++++++-
> hw/ioapic.c | 20 ++++++++++---
> hw/mc146818rtc.c | 83 ++++++++++++++++++++++++++++++++++-------------------
> hw/pc.c | 29 ++++++++++++++++--
> 6 files changed, 141 insertions(+), 80 deletions(-)
>
> diff --git a/hw/apic.c b/hw/apic.c
> index 7fbd79b..f9587d1 100644
> --- a/hw/apic.c
> +++ b/hw/apic.c
> @@ -123,10 +123,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);
> @@ -239,12 +237,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:
> @@ -261,11 +259,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;
> @@ -273,34 +272,42 @@ 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];
>
> @@ -308,8 +315,8 @@ void apic_deliver_irq(uint8_t dest, uint8_t dest_mode,
> " polarity %d trigger_mode %d\n", __func__, dest, dest_mode,
> delivery_mode, vector_num, polarity, trigger_mode);
> 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)
> @@ -402,22 +409,10 @@ static void apic_update_irq(APICState *s)
> cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
> }
>
> -void apic_reset_irq_delivered(void)
> -{
> - DPRINTF_C("%s: old coalescing %d\n", __func__, apic_irq_delivered);
> - apic_irq_delivered = 0;
> -}
> -
> -int apic_get_irq_delivered(void)
> -{
> - DPRINTF_C("%s: returning coalescing %d\n", __func__, apic_irq_delivered);
> - 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);
> - DPRINTF_C("%s: coalescing %d\n", __func__, apic_irq_delivered);
> + int ret = get_bit(s->irr, vector_num) ? QEMU_IRQ_COALESCED
> + : QEMU_IRQ_DELIVERED;
>
> set_bit(s->irr, vector_num);
> if (trigger_mode)
> @@ -425,6 +420,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 e1954f4..738d98a 100644
> --- a/hw/apic.h
> +++ b/hw/apic.h
> @@ -2,17 +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 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 f743ee8..09150c4 100644
> --- a/hw/i8259.c
> +++ b/hw/i8259.c
> @@ -189,6 +189,9 @@ int64_t irq_time[16];
> static void i8259_set_irq(qemu_irq irq, void *opaque, int n, int level)
> {
> PicState2 *s = opaque;
> + PicState *pic;
> + int result = QEMU_IRQ_DELIVERED;
> + int mask;
>
> #if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
> if (level != irq_level[n]) {
> @@ -205,8 +208,19 @@ static void i8259_set_irq(qemu_irq irq, void *opaque,
> int n, int level)
> irq_time[n] = qemu_get_clock(vm_clock);
> }
> #endif
> - pic_set_irq1(&s->pics[n >> 3], n & 7, level);
> + pic = &s->pics[n >> 3];
> + n &= 7;
> + mask = 1 << n;
> + if (level) {
> + if (pic->imr & mask) {
> + result = QEMU_IRQ_MASKED;
> + } else if (pic->irr & mask) {
> + result = QEMU_IRQ_COALESCED;
> + }
> + }
> + pic_set_irq1(pic, n, level);
> pic_update_irq(s);
> + qemu_irq_fire_delivery_cb(irq, level, result);
> }
>
> /* acknowledge interrupt 'irq' */
> diff --git a/hw/ioapic.c b/hw/ioapic.c
> index d818573..b54738f 100644
> --- a/hw/ioapic.c
> +++ b/hw/ioapic.c
> @@ -58,7 +58,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;
> @@ -69,12 +69,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;
> @@ -87,16 +91,21 @@ 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;
> }
>
> static void ioapic_set_irq(qemu_irq irq, void *opaque, int vector, int level)
> {
> IOAPICState *s = opaque;
> + int result = 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
> @@ -114,7 +123,7 @@ static void ioapic_set_irq(qemu_irq irq, void *opaque,
> int vector, int level)
> /* level triggered */
> if (level) {
> s->irr |= mask;
> - ioapic_service(s);
> + result = ioapic_service(s);
> } else {
> s->irr &= ~mask;
> }
> @@ -122,10 +131,11 @@ static void ioapic_set_irq(qemu_irq irq, void *opaque,
> int vector, int level)
> /* edge triggered */
> if (level) {
> s->irr |= mask;
> - ioapic_service(s);
> + result = ioapic_service(s);
> }
> }
> }
> + qemu_irq_fire_delivery_cb(irq, level, result);
> }
>
> static uint32_t ioapic_mem_readl(void *opaque, target_phys_addr_t addr)
> diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
> index c3e6a70..cbb98a4 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"
> @@ -101,7 +100,7 @@ typedef struct RTCState {
> QEMUTimer *second_timer2;
> } RTCState;
>
> -static void rtc_irq_raise(qemu_irq irq)
> +static void rtc_irq_raise(RTCState *s, IRQMsg *msg)
> {
> /* When HPET is operating in legacy mode, RTC interrupts are disabled
> * We block qemu_irq_raise, but not qemu_irq_lower, in case legacy
> @@ -109,9 +108,14 @@ 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()) {
> + if (msg) {
> + msg->delivery_cb(s->irq, s, -1, -1, QEMU_IRQ_MASKED);
Shouldn't you use qemu_irq_fire_delivery_cb() here?
> + }
> + return;
> + }
> #endif
> - qemu_irq_raise(irq);
> + qemu_irq_raise_msg(s->irq, msg);
> }
>
> static void rtc_set_time(RTCState *s);
> @@ -131,20 +135,41 @@ static void rtc_coalesced_timer_update(RTCState *s)
> }
> }
>
> +static void rtc_periodic_delivery_cb(qemu_irq irq, void *opaque, int n,
> + int level, int result)
> +{
> + RTCState *s = opaque;
> +
> + if (result == QEMU_IRQ_COALESCED) {
> + s->irq_coalesced++;
> + rtc_coalesced_timer_update(s);
> + DPRINTF_C("cmos: coalesced irqs increased to %d\n",
> s->irq_coalesced);
> + }
> +}
> +
> +static void rtc_reinject_delivery_cb(qemu_irq irq, void *opaque, int n,
> + int level, int result)
> +{
> + RTCState *s = opaque;
> +
> + if (result != QEMU_IRQ_COALESCED) {
> + s->irq_coalesced--;
> + DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
> s->irq_coalesced);
> + }
> +}
> +
> static void rtc_coalesced_timer(void *opaque)
> {
> RTCState *s = opaque;
> + IRQMsg msg = {
> + .delivery_cb = rtc_reinject_delivery_cb,
> + .delivery_opaque = s,
> + };
>
> if (s->irq_coalesced != 0) {
> - apic_reset_irq_delivered();
> s->cmos_data[RTC_REG_C] |= 0xc0;
> DPRINTF_C("cmos: injecting from timer\n");
> - rtc_irq_raise(s->irq);
> - if (apic_get_irq_delivered()) {
> - s->irq_coalesced--;
> - DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
> - s->irq_coalesced);
> - }
> + rtc_irq_raise(s, &msg);
> }
>
> rtc_coalesced_timer_update(s);
> @@ -203,19 +228,18 @@ static void rtc_periodic_timer(void *opaque)
> s->cmos_data[RTC_REG_C] |= 0xc0;
> #ifdef TARGET_I386
> 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()) {
> - s->irq_coalesced++;
> - rtc_coalesced_timer_update(s);
> - DPRINTF_C("cmos: coalesced irqs increased to %d\n",
> - s->irq_coalesced);
> + IRQMsg msg = {
> + .delivery_cb = rtc_periodic_delivery_cb,
> + .delivery_opaque = s,
> + };
> +
> + if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) {
> + s->irq_reinject_on_ack_count = 0;
> }
> + rtc_irq_raise(s, &msg);
> } else
> #endif
> - rtc_irq_raise(s->irq);
> + rtc_irq_raise(s, NULL);
> }
> if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
> /* Not square wave at all but we don't want 2048Hz interrupts!
> @@ -444,7 +468,7 @@ static void rtc_update_second2(void *opaque)
> s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
>
> s->cmos_data[RTC_REG_C] |= 0xa0;
> - rtc_irq_raise(s->irq);
> + rtc_irq_raise(s, NULL);
> }
> }
>
> @@ -452,7 +476,7 @@ static void rtc_update_second2(void *opaque)
> s->cmos_data[RTC_REG_C] |= REG_C_UF;
> if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
> s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
> - rtc_irq_raise(s->irq);
> + rtc_irq_raise(s, NULL);
> }
>
> /* clear update in progress bit */
> @@ -488,15 +512,14 @@ static uint32_t cmos_ioport_read(void *opaque, uint32_t
> addr)
> #ifdef TARGET_I386
> if(s->irq_coalesced &&
> s->irq_reinject_on_ack_count < RTC_REINJECT_ON_ACK_COUNT)
> {
> + IRQMsg msg = {
> + .delivery_cb = rtc_reinject_delivery_cb,
> + .delivery_opaque = s,
> + };
> +
> s->irq_reinject_on_ack_count++;
> - apic_reset_irq_delivered();
> DPRINTF_C("cmos: injecting on ack\n");
> - qemu_irq_raise(s->irq);
> - if (apic_get_irq_delivered()) {
> - s->irq_coalesced--;
> - DPRINTF_C("cmos: coalesced irqs decreased to %d\n",
> - s->irq_coalesced);
> - }
> + qemu_irq_raise_msg(s->irq, &msg);
> break;
> }
> #endif
> diff --git a/hw/pc.c b/hw/pc.c
> index 20057ca..6129e59 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -77,16 +77,37 @@ struct e820_table {
>
> static struct e820_table e820_table;
>
> +static void isa_irq_delivery_cb(qemu_irq irq, void *opaque, int n, int level,
> + int result)
> +{
> + int *result_ptr = opaque;
> +
> + *result_ptr = result;
> +}
> +
> void isa_irq_handler(qemu_irq irq, void *opaque, int n, int level)
> {
> - IsaIrqState *isa = (IsaIrqState *)opaque;
> + int result = QEMU_IRQ_MASKED;
> + IRQMsg msg = {
> + .delivery_cb = isa_irq_delivery_cb,
> + };
> + IsaIrqState *isa = opaque;
> + int ioapic_result;
>
> DPRINTF("isa_irqs: %s irq %d\n", level? "raise" : "lower", n);
> if (n < 16) {
> - qemu_set_irq(isa->i8259[n], level);
> + msg.delivery_opaque = &result;
> + qemu_set_irq_msg(isa->i8259[n], level, &msg);
> + }
> + if (isa->ioapic) {
> + msg.delivery_opaque = &ioapic_result;
> + qemu_set_irq_msg(isa->ioapic[n], level, &msg);
> + if (ioapic_result == QEMU_IRQ_DELIVERED ||
> + result == QEMU_IRQ_MASKED) {
> + result = ioapic_result;
> + }
> }
> - if (isa->ioapic)
> - qemu_set_irq(isa->ioapic[n], level);
> + qemu_irq_fire_delivery_cb(irq, level, result);
> };
>
> static void ioport80_write(void *opaque, uint32_t addr, uint32_t data)
> --
> 1.6.0.2
>
>
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, (continued)
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, Blue Swirl, 2010/06/13
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, Paul Brook, 2010/06/13
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, Blue Swirl, 2010/06/13
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, Paul Brook, 2010/06/13
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, Blue Swirl, 2010/06/13
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, Paul Brook, 2010/06/13
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, Paul Brook, 2010/06/13
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, Blue Swirl, 2010/06/13
- Re: [Qemu-devel] [PATCH 09/16] Enable message delivery via IRQs, Gleb Natapov, 2010/06/14
[Qemu-devel] [PATCH 10/16] x86: Refactor RTC IRQ coalescing workaround, Jan Kiszka, 2010/06/06
- [Qemu-devel] Re: [PATCH 10/16] x86: Refactor RTC IRQ coalescing workaround,
Blue Swirl <=
[Qemu-devel] [PATCH 11/16] hpet/rtc: Rework RTC IRQ replacement by HPET, Jan Kiszka, 2010/06/06
[Qemu-devel] [PATCH 12/16] hpet: Drop static state, Jan Kiszka, 2010/06/06
[Qemu-devel] [PATCH 14/16] vmstate: Add VMSTATE_STRUCT_VARRAY_UINT8, Jan Kiszka, 2010/06/06
[Qemu-devel] [PATCH 15/16] hpet: Make number of timers configurable, Jan Kiszka, 2010/06/06
[Qemu-devel] [PATCH 16/16] hpet: Add MSI support, Jan Kiszka, 2010/06/06