Message ID | 29c348b1e7c8c88759914a55015d72ee8c02fc1a.1275811861.git.jan.kiszka@web.de |
---|---|
State | New |
Headers | show |
On Sun, Jun 6, 2010 at 8:11 AM, Jan Kiszka <jan.kiszka@web.de> wrote: > From: Jan Kiszka <jan.kiszka@siemens.com> > > 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 <jan.kiszka@siemens.com> > --- > 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 > >
Blue Swirl wrote: > On Sun, Jun 6, 2010 at 8:11 AM, Jan Kiszka <jan.kiszka@web.de> wrote: >> From: Jan Kiszka <jan.kiszka@siemens.com> >> >> 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 <jan.kiszka@siemens.com> >> --- >> 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. s->irqs[RTC_ISA_IRQ].msg is NULL when qemu_set_irq_msg returned, msg itself will not "leak" out of the qemu_irq subsystem. Jan
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); + } +} + 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]);