From patchwork Mon May 24 20:13:41 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jan Kiszka X-Patchwork-Id: 53469 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id 7D96BB7D7B for ; Tue, 25 May 2010 06:46:24 +1000 (EST) Received: from localhost ([127.0.0.1]:35211 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OGeXL-0004lB-Ry for incoming@patchwork.ozlabs.org; Mon, 24 May 2010 16:46:11 -0400 Received: from [140.186.70.92] (port=41197 helo=eggs.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1OGe3j-00026e-EF for qemu-devel@nongnu.org; Mon, 24 May 2010 16:15:40 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.69) (envelope-from ) id 1OGe3V-0000ON-86 for qemu-devel@nongnu.org; Mon, 24 May 2010 16:15:35 -0400 Received: from fmmailgate03.web.de ([217.72.192.234]:51205) by eggs.gnu.org with esmtp (Exim 4.69) (envelope-from ) id 1OGe3R-0000Nl-1X for qemu-devel@nongnu.org; Mon, 24 May 2010 16:15:20 -0400 Received: from smtp05.web.de ( [172.20.4.166]) by fmmailgate03.web.de (Postfix) with ESMTP id 58EE915209490; Mon, 24 May 2010 22:13:57 +0200 (CEST) Received: from [88.65.39.229] (helo=localhost.localdomain) by smtp05.web.de with asmtp (TLSv1:AES256-SHA:256) (WEB.DE 4.110 #4) id 1OGe28-0004UY-03; Mon, 24 May 2010 22:13:56 +0200 From: Jan Kiszka To: qemu-devel@nongnu.org Date: Mon, 24 May 2010 22:13:41 +0200 Message-Id: <44bf86c07e89667d264c6271f2c3ee5a35696cce.1274732025.git.jan.kiszka@web.de> X-Mailer: git-send-email 1.6.0.2 In-Reply-To: References: In-Reply-To: References: X-Sender: jan.kiszka@web.de X-Provags-ID: V01U2FsdGVkX19tWX7/UFtdAt7i8einqgcUb6i0LQM162SIy3nB TpJH/wPVx4u2vT8YDc/XiwYu9gRK3hq47GqJzCGug6qi3jMNf8 kPpEuGIjY= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.4-2.6 Cc: blue Swirl , Jan Kiszka , Juan Quintela Subject: [Qemu-devel] [RFT][PATCH 08/15] x86: Refactor RTC IRQ coalescing workaround X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org From: Jan Kiszka 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 --- 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);