factor out PM_TMR logic. Later This will be used by ich9 acpi. Also fixes the same bug in vt82c686.c that was fixed by the following commits.
> commit 055479feab63607b8042bb8ebb2e0523f17cbc4e > Author: aliguori <aliguori@c046a42c-6fe2-441c-8c8c-71466251a162> > Date: Wed Jan 21 16:31:20 2009 +0000 > > Always return latest pmsts instead of the old one (Xiantao Zhang) > > It may lead to the issue when booting windows guests with acpi=1 > if return the old pmsts. > > Signed-off-by: Xiantao Zhang <xiantao.zh...@intel.com> > Signed-off-by: Anthony Liguori <aligu...@us.ibm.com> Cc: Blue Swirl <blauwir...@gmail.com> Cc: Huacai Chen <zltjiang...@gmail.com> Cc: Aurelien Jarno <aurel...@aurel32.net> Signed-off-by: Isaku Yamahata <yamah...@valinux.co.jp> --- Change v8 -> v9: - qemu_get_clock_ns() and so on. Changes v7 -> v8: - vt82c686.c --- hw/acpi.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ hw/acpi.h | 24 ++++++++++++++++++++++++ hw/acpi_piix4.c | 45 ++++++++++++--------------------------------- hw/vt82c686.c | 47 +++++++++++++++-------------------------------- 4 files changed, 96 insertions(+), 65 deletions(-) diff --git a/hw/acpi.c b/hw/acpi.c index 8071e7b..08cb126 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -197,3 +197,48 @@ out: } return -1; } + +/* ACPI PM_TMR */ +void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable) +{ + int64_t expire_time; + + /* schedule a timer interruption if needed */ + if (enable) { + expire_time = muldiv64(tmr->overflow_time, get_ticks_per_sec(), + PM_TIMER_FREQUENCY); + qemu_mod_timer(tmr->timer, expire_time); + } else { + qemu_del_timer(tmr->timer); + } +} + +void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr) +{ + int64_t d = acpi_pm_tmr_get_clock(); + tmr->overflow_time = (d + 0x800000LL) & ~0x7fffffLL; +} + +uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr) +{ + uint32_t d = acpi_pm_tmr_get_clock();; + return d & 0xffffff; +} + +static void acpi_pm_tmr_timer(void *opaque) +{ + ACPIPMTimer *tmr = opaque; + tmr->update_sci(tmr); +} + +void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci) +{ + tmr->update_sci = update_sci; + tmr->timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, tmr); +} + +void acpi_pm_tmr_reset(ACPIPMTimer *tmr) +{ + tmr->overflow_time = 0; + qemu_del_timer(tmr->timer); +} diff --git a/hw/acpi.h b/hw/acpi.h index 5949958..fc42501 100644 --- a/hw/acpi.h +++ b/hw/acpi.h @@ -74,5 +74,29 @@ #define ACPI_BITMASK_ARB_DISABLE 0x0001 /* PM_TMR */ +struct ACPIPMTimer; +typedef struct ACPIPMTimer ACPIPMTimer; + +typedef void (*acpi_update_sci_fn)(ACPIPMTimer *tmr); + +struct ACPIPMTimer { + QEMUTimer *timer; + int64_t overflow_time; + + acpi_update_sci_fn update_sci; +}; + +void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable); +void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr); +uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr); +void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci); +void acpi_pm_tmr_reset(ACPIPMTimer *tmr); + +#include "qemu-timer.h" +static inline int64_t acpi_pm_tmr_get_clock(void) +{ + return muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, + get_ticks_per_sec()); +} #endif /* !QEMU_HW_ACPI_H */ diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c index 0b2bc97..d5f631a 100644 --- a/hw/acpi_piix4.c +++ b/hw/acpi_piix4.c @@ -60,8 +60,7 @@ typedef struct PIIX4PMState { APMState apm; - QEMUTimer *tmr_timer; - int64_t tmr_overflow_time; + ACPIPMTimer tmr; PMSMBus smb; uint32_t smb_io_base; @@ -82,20 +81,10 @@ static void piix4_acpi_system_hot_add_init(PCIBus *bus, PIIX4PMState *s); #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 -static uint32_t get_pmtmr(PIIX4PMState *s) -{ - uint32_t d; - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - return d & 0xffffff; -} - static int get_pmsts(PIIX4PMState *s) { - int64_t d; - - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, - get_ticks_per_sec()); - if (d >= s->tmr_overflow_time) + int64_t d = acpi_pm_tmr_get_clock(); + if (d >= s->tmr.overflow_time) s->pmsts |= ACPI_BITMASK_TIMER_STATUS; return s->pmsts; } @@ -103,7 +92,6 @@ static int get_pmsts(PIIX4PMState *s) static void pm_update_sci(PIIX4PMState *s) { int sci_level, pmsts; - int64_t expire_time; pmsts = get_pmsts(s); sci_level = (((pmsts & s->pmen) & @@ -115,19 +103,13 @@ static void pm_update_sci(PIIX4PMState *s) qemu_set_irq(s->irq, sci_level); /* schedule a timer interruption if needed */ - if ((s->pmen & ACPI_BITMASK_TIMER_ENABLE) && - !(pmsts & ACPI_BITMASK_TIMER_STATUS)) { - expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), - PM_TIMER_FREQUENCY); - qemu_mod_timer(s->tmr_timer, expire_time); - } else { - qemu_del_timer(s->tmr_timer); - } + acpi_pm_tmr_update(&s->tmr, (s->pmen & ACPI_BITMASK_TIMER_ENABLE) && + !(pmsts & ACPI_BITMASK_TIMER_STATUS)); } -static void pm_tmr_timer(void *opaque) +static void pm_tmr_timer(ACPIPMTimer *tmr) { - PIIX4PMState *s = opaque; + PIIX4PMState *s = container_of(tmr, PIIX4PMState, tmr); pm_update_sci(s); } @@ -144,14 +126,11 @@ static void pm_ioport_write(IORange *ioport, uint64_t addr, unsigned width, switch(addr) { case 0x00: { - int64_t d; int pmsts; pmsts = get_pmsts(s); if (pmsts & val & ACPI_BITMASK_TIMER_STATUS) { /* if TMRSTS is reset, then compute the new overflow time */ - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, - get_ticks_per_sec()); - s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; + acpi_pm_tmr_calc_overflow_time(&s->tmr); } s->pmsts &= ~val; pm_update_sci(s); @@ -210,7 +189,7 @@ static void pm_ioport_read(IORange *ioport, uint64_t addr, unsigned width, val = s->pmcntrl; break; case 0x08: - val = get_pmtmr(s); + val = acpi_pm_tmr_get(&s->tmr); break; default: val = 0; @@ -315,8 +294,8 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_UINT16(pmen, PIIX4PMState), VMSTATE_UINT16(pmcntrl, PIIX4PMState), VMSTATE_STRUCT(apm, PIIX4PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(tmr_timer, PIIX4PMState), - VMSTATE_INT64(tmr_overflow_time, PIIX4PMState), + VMSTATE_TIMER(tmr.timer, PIIX4PMState), + VMSTATE_INT64(tmr.overflow_time, PIIX4PMState), VMSTATE_STRUCT(gpe, PIIX4PMState, 2, vmstate_gpe, struct gpe_regs), VMSTATE_STRUCT(pci0_status, PIIX4PMState, 2, vmstate_pci_status, struct pci_status), @@ -413,7 +392,7 @@ static int piix4_pm_initfn(PCIDevice *dev) register_ioport_write(s->smb_io_base, 64, 1, smb_ioport_writeb, &s->smb); register_ioport_read(s->smb_io_base, 64, 1, smb_ioport_readb, &s->smb); - s->tmr_timer = qemu_new_timer_ns(vm_clock, pm_tmr_timer, s); + acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); qemu_system_powerdown = *qemu_allocate_irqs(piix4_powerdown, s, 1); diff --git a/hw/vt82c686.c b/hw/vt82c686.c index 818460d..6f9c384 100644 --- a/hw/vt82c686.c +++ b/hw/vt82c686.c @@ -160,8 +160,7 @@ typedef struct VT686PMState { uint16_t pmen; uint16_t pmcntrl; APMState apm; - QEMUTimer *tmr_timer; - int64_t tmr_overflow_time; + ACPIPMTimer tmr; PMSMBus smb; uint32_t smb_io_base; } VT686PMState; @@ -183,45 +182,31 @@ typedef struct VT686MC97State { #define ACPI_ENABLE 0xf1 #define ACPI_DISABLE 0xf0 -static uint32_t get_pmtmr(VT686PMState *s) -{ - uint32_t d; - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - return d & 0xffffff; -} - static int get_pmsts(VT686PMState *s) { - int64_t d; - int pmsts; - pmsts = s->pmsts; - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - if (d >= s->tmr_overflow_time) - s->pmsts |= TMROF_EN; - return pmsts; + int64_t d = acpi_pm_tmr_get_clock(); + if (d >= s->tmr.overflow_time) { + s->pmsts |= ACPI_BITMASK_TIMER_STATUS; + } + return s->pmsts; } static void pm_update_sci(VT686PMState *s) { int sci_level, pmsts; - int64_t expire_time; pmsts = get_pmsts(s); sci_level = (((pmsts & s->pmen) & (RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0); qemu_set_irq(s->dev.irq[0], sci_level); /* schedule a timer interruption if needed */ - if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) { - expire_time = muldiv64(s->tmr_overflow_time, get_ticks_per_sec(), PM_TIMER_FREQUENCY); - qemu_mod_timer(s->tmr_timer, expire_time); - } else { - qemu_del_timer(s->tmr_timer); - } + acpi_pm_tmr_update(&s->tmr, (s->pmen & ACPI_BITMASK_TIMER_ENABLE) && + !(pmsts & ACPI_BITMASK_TIMER_STATUS)); } -static void pm_tmr_timer(void *opaque) +static void pm_tmr_timer(ACPIPMTimer *tmr) { - VT686PMState *s = opaque; + VT686PMState *s = container_of(tmr, VT686PMState, tmr); pm_update_sci(s); } @@ -233,13 +218,11 @@ static void pm_ioport_writew(void *opaque, uint32_t addr, uint32_t val) switch (addr) { case 0x00: { - int64_t d; int pmsts; pmsts = get_pmsts(s); if (pmsts & val & TMROF_EN) { /* if TMRSTS is reset, then compute the new overflow time */ - d = muldiv64(qemu_get_clock_ns(vm_clock), PM_TIMER_FREQUENCY, get_ticks_per_sec()); - s->tmr_overflow_time = (d + 0x800000LL) & ~0x7fffffLL; + acpi_pm_tmr_calc_overflow_time(&s->tmr); } s->pmsts &= ~val; pm_update_sci(s); @@ -310,7 +293,7 @@ static uint32_t pm_ioport_readl(void *opaque, uint32_t addr) addr &= 0x0f; switch (addr) { case 0x08: - val = get_pmtmr(s); + val = acpi_pm_tmr_get(&s->tmr); break; default: val = 0; @@ -365,8 +348,8 @@ static const VMStateDescription vmstate_acpi = { VMSTATE_UINT16(pmen, VT686PMState), VMSTATE_UINT16(pmcntrl, VT686PMState), VMSTATE_STRUCT(apm, VT686PMState, 0, vmstate_apm, APMState), - VMSTATE_TIMER(tmr_timer, VT686PMState), - VMSTATE_INT64(tmr_overflow_time, VT686PMState), + VMSTATE_TIMER(tmr.timer, VT686PMState), + VMSTATE_INT64(tmr.overflow_time, VT686PMState), VMSTATE_END_OF_LIST() } }; @@ -486,7 +469,7 @@ static int vt82c686b_pm_initfn(PCIDevice *dev) apm_init(&s->apm, NULL, s); - s->tmr_timer = qemu_new_timer_ns(vm_clock, pm_tmr_timer, s); + acpi_pm_tmr_init(&s->tmr, pm_tmr_timer); pm_smbus_init(&s->dev.qdev, &s->smb); -- 1.7.1.1