factor out PM_TMR logic. Later This will be used by ich9 acpi. Signed-off-by: Isaku Yamahata <yamah...@valinux.co.jp> --- hw/acpi.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ hw/acpi.h | 24 ++++++++++++++++++++++++ hw/acpi_piix4.c | 45 ++++++++++++--------------------------------- 3 files changed, 81 insertions(+), 33 deletions(-)
diff --git a/hw/acpi.c b/hw/acpi.c index e9bcf18..bd987e0 100644 --- a/hw/acpi.c +++ b/hw/acpi.c @@ -217,3 +217,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(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..1f9132f 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(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 5bbc2b5..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(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(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(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(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); -- 1.7.1.1