diff --git a/hw/acpi.c b/hw/acpi.c index 8071e7bebaf67cb312fe05b88231f8e9a02f97b3..08cb12673b5dd3580b264e7a1d24cfb948444e4e 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 5949958067d4c220fcdc92be5d9306699bb96ec6..fc425012b382434cca789ad29718aabc8702ff2c 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 74044ddd9b3639486eebafc6602fcf3221e171c8..e4ba8fc2525b11c168d3750aa4cfc55fe281cddd 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); @@ -211,7 +190,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; @@ -316,8 +295,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), @@ -414,7 +393,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 818460d716f35f4979b2549bbbc75359f2bbbcfe..6f9c3847cb37165cb57ea70221f454ee146781c3 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);