[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] Re: [PATCH 11/16] hpet/rtc: Rework RTC IRQ replacement by H
From: |
Blue Swirl |
Subject: |
[Qemu-devel] Re: [PATCH 11/16] hpet/rtc: Rework RTC IRQ replacement by HPET |
Date: |
Sun, 6 Jun 2010 08:53:07 +0000 |
On Sun, Jun 6, 2010 at 8:11 AM, Jan Kiszka <address@hidden> wrote:
> From: Jan Kiszka <address@hidden>
>
> Allow the intercept the RTC IRQ for the HPET legacy mode. Then push
> routing to IRQ8 completely into the HPET. This allows to turn
> hpet_in_legacy_mode() into a private function. Furthermore, this stops
> the RTC from clearing IRQ8 even if the HPET is in control.
>
> This patch comes with a side effect: The RTC timers will no longer be
> stoppend when there is no IRQ consumer, possibly causing a minor
> performance degration. But as the guest may want to redirect the RTC to
> the SCI in that mode, it should normally disable unused IRQ source
> anyway.
>
> Signed-off-by: Jan Kiszka <address@hidden>
> ---
> hw/hpet.c | 42 +++++++++++++++++++++++++++++++++++-------
> hw/hpet_emul.h | 4 ----
> hw/mc146818rtc.c | 54
> +++++++++++++++---------------------------------------
> hw/mc146818rtc.h | 4 +++-
> hw/mips_jazz.c | 2 +-
> hw/mips_malta.c | 2 +-
> hw/mips_r4k.c | 2 +-
> hw/pc.c | 14 ++++++++------
> hw/ppc_prep.c | 2 +-
> 9 files changed, 65 insertions(+), 61 deletions(-)
>
> diff --git a/hw/hpet.c b/hw/hpet.c
> index 041dd84..d26cad5 100644
> --- a/hw/hpet.c
> +++ b/hw/hpet.c
> @@ -30,6 +30,7 @@
> #include "qemu-timer.h"
> #include "hpet_emul.h"
> #include "sysbus.h"
> +#include "mc146818rtc.h"
>
> //#define HPET_DEBUG
> #ifdef HPET_DEBUG
> @@ -58,6 +59,7 @@ typedef struct HPETState {
> SysBusDevice busdev;
> uint64_t hpet_offset;
> qemu_irq irqs[HPET_NUM_IRQ_ROUTES];
> + uint8_t rtc_irq_level;
> HPETTimer timer[HPET_NUM_TIMERS];
>
> /* Memory-mapped, software visible registers */
> @@ -69,12 +71,9 @@ typedef struct HPETState {
>
> static HPETState *hpet_statep;
>
> -uint32_t hpet_in_legacy_mode(void)
> +static uint32_t hpet_in_legacy_mode(HPETState *s)
> {
> - if (!hpet_statep) {
> - return 0;
> - }
> - return hpet_statep->config & HPET_CFG_LEGACY;
> + return s->config & HPET_CFG_LEGACY;
> }
>
> static uint32_t timer_int_route(struct HPETTimer *timer)
> @@ -166,12 +165,12 @@ static void update_irq(struct HPETTimer *timer)
> {
> int route;
>
> - if (timer->tn <= 1 && hpet_in_legacy_mode()) {
> + if (timer->tn <= 1 && hpet_in_legacy_mode(timer->state)) {
> /* if LegacyReplacementRoute bit is set, HPET specification requires
> * timer0 be routed to IRQ0 in NON-APIC or IRQ2 in the I/O APIC,
> * timer1 be routed to IRQ8 in NON-APIC or IRQ8 in the I/O APIC.
> */
> - route = (timer->tn == 0) ? 0 : 8;
> + route = (timer->tn == 0) ? 0 : RTC_ISA_IRQ;
> } else {
> route = timer_int_route(timer);
> }
> @@ -515,8 +514,10 @@ static void hpet_ram_writel(void *opaque,
> target_phys_addr_t addr,
> /* i8254 and RTC are disabled when HPET is in legacy mode */
> if (activating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
> hpet_pit_disable();
> + qemu_irq_lower(s->irqs[RTC_ISA_IRQ]);
> } else if (deactivating_bit(old_val, new_val, HPET_CFG_LEGACY)) {
> hpet_pit_enable();
> + qemu_set_irq(s->irqs[RTC_ISA_IRQ], s->rtc_irq_level);
> }
> break;
> case HPET_CFG + 4:
> @@ -607,6 +608,30 @@ static void hpet_reset(DeviceState *d)
> count = 1;
> }
>
> +static void hpet_rtc_delivery_cb(qemu_irq irq, void *opaque, int n, int
> level,
> + int result)
> +{
> + qemu_irq orig_irq = opaque;
> +
> + qemu_irq_fire_delivery_cb(orig_irq, level, result);
> +}
> +
> +static void hpet_handle_rtc_irq(qemu_irq irq, void *opaque, int n, int level)
> +{
> + HPETState *s = FROM_SYSBUS(HPETState, opaque);
> + IRQMsg msg = {
> + .delivery_cb = hpet_rtc_delivery_cb,
> + .delivery_opaque = irq,
> + };
> +
> + s->rtc_irq_level = level;
> + if (hpet_in_legacy_mode(s)) {
> + qemu_irq_fire_delivery_cb(irq, level, QEMU_IRQ_MASKED);
> + } else {
> + qemu_set_irq_msg(s->irqs[RTC_ISA_IRQ], level, &msg);
This is the problem with passing around stack allocated objects: after
this function finishes, s->irqs[RTC_ISA_IRQ].msg is a dangling pointer
to some stack space.
> + }
> +}
> +
> static int hpet_init(SysBusDevice *dev)
> {
> HPETState *s = FROM_SYSBUS(HPETState, dev);
> @@ -625,6 +650,9 @@ static int hpet_init(SysBusDevice *dev)
> timer->state = s;
> }
>
> + isa_reserve_irq(RTC_ISA_IRQ);
> + qdev_init_gpio_in(&dev->qdev, hpet_handle_rtc_irq, 1);
> +
> /* HPET Area */
> iomemtype = cpu_register_io_memory(hpet_ram_read,
> hpet_ram_write, s);
> diff --git a/hw/hpet_emul.h b/hw/hpet_emul.h
> index 785f850..9c268cc 100644
> --- a/hw/hpet_emul.h
> +++ b/hw/hpet_emul.h
> @@ -47,8 +47,4 @@
> #define HPET_TN_INT_ROUTE_CAP_SHIFT 32
> #define HPET_TN_CFG_BITS_READONLY_OR_RESERVED 0xffff80b1U
>
> -#if defined TARGET_I386
> -extern uint32_t hpet_in_legacy_mode(void);
> -#endif
> -
> #endif
> diff --git a/hw/mc146818rtc.c b/hw/mc146818rtc.c
> index cbb98a4..ac82810 100644
> --- a/hw/mc146818rtc.c
> +++ b/hw/mc146818rtc.c
> @@ -26,7 +26,6 @@
> #include "sysemu.h"
> #include "pc.h"
> #include "isa.h"
> -#include "hpet_emul.h"
> #include "mc146818rtc.h"
>
> //#define DEBUG_CMOS
> @@ -100,24 +99,6 @@ typedef struct RTCState {
> QEMUTimer *second_timer2;
> } RTCState;
>
> -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
> - * mode is established while interrupt is raised. We want it to
> - * be lowered in any case
> - */
> -#if defined TARGET_I386
> - if (hpet_in_legacy_mode()) {
> - if (msg) {
> - msg->delivery_cb(s->irq, s, -1, -1, QEMU_IRQ_MASKED);
> - }
> - return;
> - }
> -#endif
> - qemu_irq_raise_msg(s->irq, msg);
> -}
> -
> static void rtc_set_time(RTCState *s);
> static void rtc_copy_date(RTCState *s);
>
> @@ -169,7 +150,7 @@ static void rtc_coalesced_timer(void *opaque)
> if (s->irq_coalesced != 0) {
> s->cmos_data[RTC_REG_C] |= 0xc0;
> DPRINTF_C("cmos: injecting from timer\n");
> - rtc_irq_raise(s, &msg);
> + qemu_irq_raise_msg(s->irq, &msg);
> }
>
> rtc_coalesced_timer_update(s);
> @@ -180,19 +161,10 @@ static void rtc_timer_update(RTCState *s, int64_t
> current_time)
> {
> int period_code, period;
> int64_t cur_clock, next_irq_clock;
> - int enable_pie;
>
> period_code = s->cmos_data[RTC_REG_A] & 0x0f;
> -#if defined TARGET_I386
> - /* disable periodic timer if hpet is in legacy mode, since interrupts are
> - * disabled anyway.
> - */
> - enable_pie = !hpet_in_legacy_mode();
> -#else
> - enable_pie = 1;
> -#endif
> if (period_code != 0
> - && (((s->cmos_data[RTC_REG_B] & REG_B_PIE) && enable_pie)
> + && ((s->cmos_data[RTC_REG_B] & REG_B_PIE)
> || ((s->cmos_data[RTC_REG_B] & REG_B_SQWE) && s->sqw_irq))) {
> if (period_code <= 2)
> period_code += 7;
> @@ -236,10 +208,10 @@ static void rtc_periodic_timer(void *opaque)
> if (s->irq_reinject_on_ack_count >= RTC_REINJECT_ON_ACK_COUNT) {
> s->irq_reinject_on_ack_count = 0;
> }
> - rtc_irq_raise(s, &msg);
> + qemu_irq_raise_msg(s->irq, &msg);
> } else
> #endif
> - rtc_irq_raise(s, NULL);
> + qemu_irq_raise(s->irq);
> }
> if (s->cmos_data[RTC_REG_B] & REG_B_SQWE) {
> /* Not square wave at all but we don't want 2048Hz interrupts!
> @@ -468,15 +440,15 @@ 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, NULL);
> + qemu_irq_raise(s->irq);
> }
> }
>
> /* update ended interrupt */
> 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, NULL);
> + s->cmos_data[RTC_REG_C] |= REG_C_IRQF;
> + qemu_irq_raise(s->irq);
> }
>
> /* clear update in progress bit */
> @@ -629,9 +601,6 @@ static int rtc_initfn(ISADevice *dev)
> {
> RTCState *s = DO_UPCAST(RTCState, dev, dev);
> int base = 0x70;
> - int isairq = 8;
> -
> - isa_init_irq(dev, &s->irq, isairq);
>
> s->cmos_data[RTC_REG_A] = 0x26;
> s->cmos_data[RTC_REG_B] = 0x02;
> @@ -661,13 +630,20 @@ static int rtc_initfn(ISADevice *dev)
> return 0;
> }
>
> -ISADevice *rtc_init(int base_year)
> +ISADevice *rtc_init(int base_year, qemu_irq intercept_irq)
> {
> ISADevice *dev;
> + RTCState *s;
>
> dev = isa_create("mc146818rtc");
> + s = DO_UPCAST(RTCState, dev, dev);
> qdev_prop_set_int32(&dev->qdev, "base_year", base_year);
> qdev_init_nofail(&dev->qdev);
> + if (intercept_irq) {
> + s->irq = intercept_irq;
> + } else {
> + isa_init_irq(dev, &s->irq, RTC_ISA_IRQ);
> + }
> return dev;
> }
>
> diff --git a/hw/mc146818rtc.h b/hw/mc146818rtc.h
> index 6f46a68..575968c 100644
> --- a/hw/mc146818rtc.h
> +++ b/hw/mc146818rtc.h
> @@ -3,7 +3,9 @@
>
> #include "isa.h"
>
> -ISADevice *rtc_init(int base_year);
> +#define RTC_ISA_IRQ 8
> +
> +ISADevice *rtc_init(int base_year, qemu_irq intercept_irq);
> void rtc_set_memory(ISADevice *dev, int addr, int val);
> void rtc_set_date(ISADevice *dev, const struct tm *tm);
>
> diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
> index da1bf6e..5e52f59 100644
> --- a/hw/mips_jazz.c
> +++ b/hw/mips_jazz.c
> @@ -259,7 +259,7 @@ void mips_jazz_init (ram_addr_t ram_size,
> fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
>
> /* Real time clock */
> - rtc_init(1980);
> + rtc_init(1980, NULL);
> s_rtc = cpu_register_io_memory(rtc_read, rtc_write, NULL);
> cpu_register_physical_memory(0x80004000, 0x00001000, s_rtc);
>
> diff --git a/hw/mips_malta.c b/hw/mips_malta.c
> index bd86636..438e4e3 100644
> --- a/hw/mips_malta.c
> +++ b/hw/mips_malta.c
> @@ -959,7 +959,7 @@ void mips_malta_init (ram_addr_t ram_size,
> /* Super I/O */
> isa_dev = isa_create_simple("i8042");
>
> - rtc_state = rtc_init(2000);
> + rtc_state = rtc_init(2000, NULL);
> serial_isa_init(0, serial_hds[0]);
> serial_isa_init(1, serial_hds[1]);
> if (parallel_hds[0])
> diff --git a/hw/mips_r4k.c b/hw/mips_r4k.c
> index f1fcfcd..5a96dea 100644
> --- a/hw/mips_r4k.c
> +++ b/hw/mips_r4k.c
> @@ -267,7 +267,7 @@ void mips_r4k_init (ram_addr_t ram_size,
> isa_bus_new(NULL);
> isa_bus_irqs(i8259);
>
> - rtc_state = rtc_init(2000);
> + rtc_state = rtc_init(2000, NULL);
>
> /* Register 64 KB of ISA IO space at 0x14000000 */
> #ifdef TARGET_WORDS_BIGENDIAN
> diff --git a/hw/pc.c b/hw/pc.c
> index 6129e59..8460303 100644
> --- a/hw/pc.c
> +++ b/hw/pc.c
> @@ -965,6 +965,7 @@ void pc_basic_device_init(qemu_irq *isa_irq,
> int i;
> DriveInfo *fd[MAX_FD];
> PITState *pit;
> + qemu_irq rtc_irq = NULL;
> qemu_irq *a20_line;
> ISADevice *i8042;
> qemu_irq *cpu_exit_irq;
> @@ -973,19 +974,20 @@ void pc_basic_device_init(qemu_irq *isa_irq,
>
> register_ioport_write(0xf0, 1, 1, ioportF0_write, NULL);
>
> - *rtc_state = rtc_init(2000);
> -
> - qemu_register_boot_set(pc_boot_set, *rtc_state);
> -
> - pit = pit_init(0x40, isa_reserve_irq(0));
> - pcspk_init(pit);
> if (!no_hpet) {
> DeviceState *hpet = sysbus_create_simple("hpet", HPET_BASE, NULL);
>
> for (i = 0; i < 24; i++) {
> sysbus_connect_irq(sysbus_from_qdev(hpet), i, isa_irq[i]);
> }
> + rtc_irq = qdev_get_gpio_in(hpet, 0);
> }
> + *rtc_state = rtc_init(2000, rtc_irq);
> +
> + qemu_register_boot_set(pc_boot_set, *rtc_state);
> +
> + pit = pit_init(0x40, isa_reserve_irq(0));
> + pcspk_init(pit);
>
> for(i = 0; i < MAX_SERIAL_PORTS; i++) {
> if (serial_hds[i]) {
> diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
> index fd1ca86..f44a144 100644
> --- a/hw/ppc_prep.c
> +++ b/hw/ppc_prep.c
> @@ -696,7 +696,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
> pci_vga_init(pci_bus, 0, 0);
> // openpic = openpic_init(0x00000000, 0xF0000000, 1);
> // pit = pit_init(0x40, i8259[0]);
> - rtc_init(2000);
> + rtc_init(2000, NULL);
>
> if (serial_hds[0])
> serial_isa_init(0, serial_hds[0]);
> --
> 1.6.0.2
>
>
[Qemu-devel] [PATCH 10/16] x86: Refactor RTC IRQ coalescing workaround, Jan Kiszka, 2010/06/06
[Qemu-devel] [PATCH 11/16] hpet/rtc: Rework RTC IRQ replacement by HPET, Jan Kiszka, 2010/06/06
- [Qemu-devel] Re: [PATCH 11/16] hpet/rtc: Rework RTC IRQ replacement by HPET,
Blue Swirl <=
[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
[Qemu-devel] [PATCH 13/16] hpet: Add support for level-triggered interrupts, Jan Kiszka, 2010/06/06
[Qemu-devel] [PATCH 08/16] Pass IRQ object on handler invocation, Jan Kiszka, 2010/06/06