acpi, acpi_piix, vt82c686: factor out PM_TMR logic
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 055479feab
> 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.zhang@intel.com>
>     Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
Cc: Blue Swirl <blauwirbel@gmail.com>
Cc: Huacai Chen <zltjiangshi@gmail.com>
Cc: Aurelien Jarno <aurelien@aurel32.net>
Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
			
			
This commit is contained in:
		
							parent
							
								
									5145b3d1cc
								
							
						
					
					
						commit
						a54d41a8b9
					
				
							
								
								
									
										45
									
								
								hw/acpi.c
								
								
								
								
							
							
						
						
									
										45
									
								
								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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										24
									
								
								hw/acpi.h
								
								
								
								
							
							
						
						
									
										24
									
								
								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 */
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue