On Sun, June 21, 2015 9:37 pm, Paulo Alcantara wrote: > This interface provides some registers within a 32-byte range and can be > acessed through PCI-to-LPC bridge interface (PMBASE + 0x60). > > It's commonly used as a watchdog timer to detect system lockups through > SMIs that are generated -- if TCO_EN bit is set -- on every timeout. If > NO_REBOOT bit is not set in GCS (General Control and Status register), > the system will be resetted upon second timeout if TCO_RLD register > wasn't previously written to prevent timeout. > > This patch adds support to TCO watchdog logic and few other features > like mapping NMIs to SMIs (NMI2SMI_EN bit), system intruder detection, > etc. are not implemented yet. > > Signed-off-by: Paulo Alcantara <pca...@zytor.com> > --- > v1 -> v2: > * add migration support for TCO I/O device state > * wake up only when total time expired instead of every 0.6s > * some cleanup suggested by Paolo Bonzini > > v2 -> v3: > * set SECOND_TO_STS and BOOT_STS bits in TCO2_STS instead > * improve handling of TCO_LOCK bit in TCO1_CNT register > > v3 -> v4: > * fix some conflicts in hw/acpi/ich9.c after rebasing against master > * remove meaningless "use_tco" field from TCOIORegs structure > * add a object property named "enable_tco" and only enable TCO support > on pc-q35-2.4 and later > --- > hw/acpi/Makefile.objs | 2 +- > hw/acpi/ich9.c | 55 +++++++++- > hw/acpi/tco.c | 279 > +++++++++++++++++++++++++++++++++++++++++++++++++ > hw/i386/pc_q35.c | 4 +- > hw/isa/lpc_ich9.c | 15 ++- > include/hw/acpi/ich9.h | 7 +- > include/hw/acpi/tco.h | 98 +++++++++++++++++ > include/hw/boards.h | 3 +- > include/hw/i386/ich9.h | 10 +- > include/hw/i386/pc.h | 1 + > 10 files changed, 466 insertions(+), 8 deletions(-) > create mode 100644 hw/acpi/tco.c > create mode 100644 include/hw/acpi/tco.h > > diff --git a/hw/acpi/Makefile.objs b/hw/acpi/Makefile.objs > index 29d46d8..3db1f07 100644 > --- a/hw/acpi/Makefile.objs > +++ b/hw/acpi/Makefile.objs > @@ -1,4 +1,4 @@ > -common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o ich9.o pcihp.o > +common-obj-$(CONFIG_ACPI_X86) += core.o piix4.o ich9.o pcihp.o tco.o > common-obj-$(CONFIG_ACPI_CPU_HOTPLUG) += cpu_hotplug.o > common-obj-$(CONFIG_ACPI_MEMORY_HOTPLUG) += memory_hotplug.o > common-obj-$(CONFIG_ACPI) += acpi_interface.o > diff --git a/hw/acpi/ich9.c b/hw/acpi/ich9.c > index 8a64ffb..d3d9953 100644 > --- a/hw/acpi/ich9.c > +++ b/hw/acpi/ich9.c > @@ -30,6 +30,7 @@ > #include "qemu/timer.h" > #include "sysemu/sysemu.h" > #include "hw/acpi/acpi.h" > +#include "hw/acpi/tco.h" > #include "sysemu/kvm.h" > #include "exec/address-spaces.h" > > @@ -92,8 +93,16 @@ static void ich9_smi_writel(void *opaque, hwaddr addr, > uint64_t val, > unsigned width) > { > ICH9LPCPMRegs *pm = opaque; > + TCOIORegs *tr = &pm->tco_regs; > + uint64_t tco_en; > + > switch (addr) { > case 0: > + tco_en = pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN; > + /* once TCO_LOCK bit is set, TCO_EN bit cannot be overwritten */ > + if (tr->tco.cnt1 & TCO_LOCK) { > + val = (val & ~ICH9_PMIO_SMI_EN_TCO_EN) | tco_en; > + } > pm->smi_en &= ~pm->smi_en_wmask; > pm->smi_en |= (val & pm->smi_en_wmask); > break; > @@ -159,6 +168,25 @@ static const VMStateDescription vmstate_memhp_state = > { > } > }; > > +static bool vmstate_test_use_tco(void *opaque) > +{ > + ICH9LPCPMRegs *s = opaque; > + return s->enable_tco; > +} > + > +static const VMStateDescription vmstate_tco_io_state = { > + .name = "ich9_pm/tco", > + .version_id = 1, > + .minimum_version_id = 1, > + .minimum_version_id_old = 1, > + .needed = vmstate_test_use_tco, > + .fields = (VMStateField[]) { > + VMSTATE_STRUCT(tco_regs, ICH9LPCPMRegs, 1, vmstate_tco_io_sts, > + TCOIORegs), > + VMSTATE_END_OF_LIST() > + } > +}; > + > const VMStateDescription vmstate_ich9_pm = { > .name = "ich9_pm", > .version_id = 1, > @@ -179,6 +207,10 @@ const VMStateDescription vmstate_ich9_pm = { > .subsections = (const VMStateDescription*[]) { > &vmstate_memhp_state, > NULL > + }, > + .subsections = (const VMStateDescription*[]) { > + &vmstate_tco_io_state, > + NULL > } > }; > > @@ -209,7 +241,7 @@ static void pm_powerdown_req(Notifier *n, void > *opaque) > acpi_pm1_evt_power_down(&pm->acpi_regs); > } > > -void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, > +void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, bool enable_tco, > qemu_irq sci_irq) > { > memory_region_init(&pm->io, OBJECT(lpc_pci), "ich9-pm", > ICH9_PMIO_SIZE); > @@ -231,6 +263,11 @@ void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs > *pm, > "acpi-smi", 8); > memory_region_add_subregion(&pm->io, ICH9_PMIO_SMI_EN, &pm->io_smi); > > + pm->enable_tco = enable_tco; > + if (pm->enable_tco) { > + acpi_pm_tco_init(&pm->tco_regs, &pm->io); > + } > + > pm->irq = sci_irq; > qemu_register_reset(pm_reset, pm); > pm->powerdown_notifier.notify = pm_powerdown_req; > @@ -351,6 +388,18 @@ out: > error_propagate(errp, local_err); > } > > +static bool ich9_pm_get_enable_tco(Object *obj, Error **errp) > +{ > + ICH9LPCState *s = ICH9_LPC_DEVICE(obj); > + return s->pm.enable_tco; > +} > + > +static void ich9_pm_set_enable_tco(Object *obj, bool value, Error **errp) > +{ > + ICH9LPCState *s = ICH9_LPC_DEVICE(obj); > + s->pm.enable_tco = value; > +} > + > void ich9_pm_add_properties(Object *obj, ICH9LPCPMRegs *pm, Error **errp) > { > static const uint32_t gpe0_len = ICH9_PMIO_GPE0_LEN; > @@ -382,6 +431,10 @@ void ich9_pm_add_properties(Object *obj, > ICH9LPCPMRegs *pm, Error **errp) > ich9_pm_get_s4_val, > ich9_pm_set_s4_val, > NULL, pm, NULL); > + object_property_add_bool(obj, ACPI_PM_PROP_TCO_ENABLED, > + ich9_pm_get_enable_tco, > + ich9_pm_set_enable_tco, > + NULL); > } > > void ich9_pm_device_plug_cb(ICH9LPCPMRegs *pm, DeviceState *dev, Error > **errp) > diff --git a/hw/acpi/tco.c b/hw/acpi/tco.c > new file mode 100644 > index 0000000..b6af1d9 > --- /dev/null > +++ b/hw/acpi/tco.c > @@ -0,0 +1,279 @@ > +/* > + * QEMU ICH9 TCO emulation > + * > + * Copyright (c) 2015 Paulo Alcantara <pca...@zytor.com> > + * > + * Permission is hereby granted, free of charge, to any person obtaining > a copy > + * of this software and associated documentation files (the "Software"), > to deal > + * in the Software without restriction, including without limitation the > rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or > sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be > included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT > SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR > OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, > ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > IN > + * THE SOFTWARE. > + */ > +#include "qemu-common.h" > +#include "sysemu/watchdog.h" > +#include "hw/i386/ich9.h" > + > +#include "hw/acpi/tco.h" > + > +//#define DEBUG > + > +#ifdef DEBUG > +#define TCO_DEBUG(fmt, ...) \ > + do { \ > + fprintf(stderr, "%s "fmt, __func__, ## __VA_ARGS__); \ > + } while (0) > +#else > +#define TCO_DEBUG(fmt, ...) do { } while (0) > +#endif > + > +enum { > + TCO_RLD_DEFAULT = 0x0000, > + TCO_DAT_IN_DEFAULT = 0x00, > + TCO_DAT_OUT_DEFAULT = 0x00, > + TCO1_STS_DEFAULT = 0x0000, > + TCO2_STS_DEFAULT = 0x0000, > + TCO1_CNT_DEFAULT = 0x0000, > + TCO2_CNT_DEFAULT = 0x0008, > + TCO_MESSAGE1_DEFAULT = 0x00, > + TCO_MESSAGE2_DEFAULT = 0x00, > + TCO_WDCNT_DEFAULT = 0x00, > + TCO_TMR_DEFAULT = 0x0004, > + SW_IRQ_GEN_DEFAULT = 0x03, > +}; > + > +static inline void tco_timer_reload(TCOIORegs *tr) > +{ > + tr->expire_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + > + ((int64_t)(tr->tco.tmr & TCO_TMR_MASK) * TCO_TICK_NSEC); > + timer_mod(tr->tco_timer, tr->expire_time); > +} > + > +static inline void tco_timer_stop(TCOIORegs *tr) > +{ > + tr->expire_time = -1; > +} > + > +static void tco_timer_expired(void *opaque) > +{ > + TCOIORegs *tr = opaque; > + ICH9LPCPMRegs *pm = container_of(tr, ICH9LPCPMRegs, tco_regs); > + ICH9LPCState *lpc = container_of(pm, ICH9LPCState, pm); > + uint32_t gcs = pci_get_long(lpc->chip_config + ICH9_LPC_RCBA_GCS); > + > + tr->tco.rld = 0; > + tr->tco.sts1 |= TCO_TIMEOUT; > + if (++tr->timeouts_no == 2) { > + tr->tco.sts2 |= TCO_SECOND_TO_STS; > + tr->tco.sts2 |= TCO_BOOT_STS; > + tr->timeouts_no = 0; > + > + if (!(gcs & ICH9_LPC_RCBA_GCS_NO_REBOOT)) { > + watchdog_perform_action(); > + tco_timer_stop(tr); > + return; > + } > + } > + > + if (pm->smi_en & ICH9_PMIO_SMI_EN_TCO_EN) { > + ich9_generate_smi(); > + } else { > + ich9_generate_nmi(); > + } > + tr->tco.rld = tr->tco.tmr; > + tco_timer_reload(tr); > +} > + > +/* NOTE: values of 0 or 1 will be ignored by ICH */ > +static inline int can_start_tco_timer(TCOIORegs *tr) > +{ > + return !(tr->tco.cnt1 & TCO_TMR_HLT) && tr->tco.tmr > 1; > +} > + > +static uint32_t tco_ioport_readw(TCOIORegs *tr, uint32_t addr) > +{ > + uint16_t rld; > + > + switch (addr) { > + case TCO_RLD: > + if (tr->expire_time != -1) { > + int64_t now = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL); > + int64_t elapsed = (tr->expire_time - now) / TCO_TICK_NSEC; > + rld = (uint16_t)elapsed | (tr->tco.rld & ~TCO_RLD_MASK); > + } else { > + rld = tr->tco.rld; > + } > + return rld; > + case TCO_DAT_IN: > + return tr->tco.din; > + case TCO_DAT_OUT: > + return tr->tco.dout; > + case TCO1_STS: > + return tr->tco.sts1; > + case TCO2_STS: > + return tr->tco.sts2; > + case TCO1_CNT: > + return tr->tco.cnt1; > + case TCO2_CNT: > + return tr->tco.cnt2; > + case TCO_MESSAGE1: > + return tr->tco.msg1; > + case TCO_MESSAGE2: > + return tr->tco.msg2; > + case TCO_WDCNT: > + return tr->tco.wdcnt; > + case TCO_TMR: > + return tr->tco.tmr; > + case SW_IRQ_GEN: > + return tr->sw_irq_gen; > + } > + return 0; > +} > + > +static void tco_ioport_writew(TCOIORegs *tr, uint32_t addr, uint32_t val) > +{ > + switch (addr) { > + case TCO_RLD: > + tr->timeouts_no = 0; > + if (can_start_tco_timer(tr)) { > + tr->tco.rld = tr->tco.tmr; > + tco_timer_reload(tr); > + } else { > + tr->tco.rld = val; > + } > + break; > + case TCO_DAT_IN: > + tr->tco.din = val; > + tr->tco.sts1 |= SW_TCO_SMI; > + ich9_generate_smi(); > + break; > + case TCO_DAT_OUT: > + tr->tco.dout = val; > + tr->tco.sts1 |= TCO_INT_STS; > + /* TODO: cause an interrupt, as selected by the TCO_INT_SEL bits > */ > + break; > + case TCO1_STS: > + tr->tco.sts1 = val & TCO1_STS_MASK; > + break; > + case TCO2_STS: > + tr->tco.sts2 = val & TCO2_STS_MASK; > + break; > + case TCO1_CNT: > + val &= TCO1_CNT_MASK; > + /* > + * once TCO_LOCK bit is set, it can not be cleared by software. a > reset > + * is required to change this bit from 1 to 0 -- it defaults to > 0. > + */ > + tr->tco.cnt1 = val | (tr->tco.cnt1 & TCO_LOCK); > + if (can_start_tco_timer(tr)) { > + tr->tco.rld = tr->tco.tmr; > + tco_timer_reload(tr); > + } else { > + tco_timer_stop(tr); > + } > + break; > + case TCO2_CNT: > + tr->tco.cnt2 = val; > + break; > + case TCO_MESSAGE1: > + tr->tco.msg1 = val; > + break; > + case TCO_MESSAGE2: > + tr->tco.msg2 = val; > + break; > + case TCO_WDCNT: > + tr->tco.wdcnt = val; > + break; > + case TCO_TMR: > + tr->tco.tmr = val; > + break; > + case SW_IRQ_GEN: > + tr->sw_irq_gen = val; > + break; > + } > +} > + > +static uint64_t tco_io_readw(void *opaque, hwaddr addr, unsigned width) > +{ > + TCOIORegs *tr = opaque; > + return tco_ioport_readw(tr, addr); > +} > + > +static void tco_io_writew(void *opaque, hwaddr addr, uint64_t val, > + unsigned width) > +{ > + TCOIORegs *tr = opaque; > + tco_ioport_writew(tr, addr, val); > +} > + > +static const MemoryRegionOps tco_io_ops = { > + .read = tco_io_readw, > + .write = tco_io_writew, > + .valid.min_access_size = 1, > + .valid.max_access_size = 4, > + .impl.min_access_size = 1, > + .impl.max_access_size = 2, > + .endianness = DEVICE_LITTLE_ENDIAN, > +}; > + > +void acpi_pm_tco_init(TCOIORegs *tr, MemoryRegion *parent) > +{ > + *tr = (TCOIORegs) { > + .tco = { > + .rld = TCO_RLD_DEFAULT, > + .din = TCO_DAT_IN_DEFAULT, > + .dout = TCO_DAT_OUT_DEFAULT, > + .sts1 = TCO1_STS_DEFAULT, > + .sts2 = TCO2_STS_DEFAULT, > + .cnt1 = TCO1_CNT_DEFAULT, > + .cnt2 = TCO2_CNT_DEFAULT, > + .msg1 = TCO_MESSAGE1_DEFAULT, > + .msg2 = TCO_MESSAGE2_DEFAULT, > + .wdcnt = TCO_WDCNT_DEFAULT, > + .tmr = TCO_TMR_DEFAULT, > + }, > + .sw_irq_gen = SW_IRQ_GEN_DEFAULT, > + .tco_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, > tco_timer_expired, tr), > + .expire_time = -1, > + .timeouts_no = 0, > + }; > + memory_region_init_io(&tr->io, memory_region_owner(parent), > + &tco_io_ops, tr, "sm-tco", ICH9_PMIO_TCO_LEN); > + memory_region_add_subregion(parent, ICH9_PMIO_TCO_RLD, &tr->io); > +} > + > +const VMStateDescription vmstate_tco_io_sts = { > + .name = "tco io device status", > + .version_id = 1, > + .minimum_version_id = 1, > + .minimum_version_id_old = 1, > + .fields = (VMStateField[]) { > + VMSTATE_UINT16(tco.rld, TCOIORegs), > + VMSTATE_UINT8(tco.din, TCOIORegs), > + VMSTATE_UINT8(tco.dout, TCOIORegs), > + VMSTATE_UINT16(tco.sts1, TCOIORegs), > + VMSTATE_UINT16(tco.sts2, TCOIORegs), > + VMSTATE_UINT16(tco.cnt1, TCOIORegs), > + VMSTATE_UINT16(tco.cnt2, TCOIORegs), > + VMSTATE_UINT8(tco.msg1, TCOIORegs), > + VMSTATE_UINT8(tco.msg2, TCOIORegs), > + VMSTATE_UINT8(tco.wdcnt, TCOIORegs), > + VMSTATE_UINT16(tco.tmr, TCOIORegs), > + VMSTATE_UINT8(sw_irq_gen, TCOIORegs), > + VMSTATE_TIMER_PTR(tco_timer, TCOIORegs), > + VMSTATE_INT64(expire_time, TCOIORegs), > + VMSTATE_UINT8(timeouts_no, TCOIORegs), > + VMSTATE_END_OF_LIST() > + } > +}; > diff --git a/hw/i386/pc_q35.c b/hw/i386/pc_q35.c > index 082cd93..7e35a36 100644 > --- a/hw/i386/pc_q35.c > +++ b/hw/i386/pc_q35.c > @@ -253,7 +253,7 @@ static void pc_q35_init(MachineState *machine) > (pc_machine->vmport != ON_OFF_AUTO_ON), > 0xff0104); > > /* connect pm stuff to lpc */ > - ich9_lpc_pm_init(lpc); > + ich9_lpc_pm_init(lpc, !mc->no_tco); > > /* ahci and SATA device, for q35 1 ahci controller is built-in */ > ahci = pci_create_simple_multifunction(host_bus, > @@ -393,6 +393,7 @@ static void pc_q35_2_4_machine_options(MachineClass > *m) > m->default_machine_opts = "firmware=bios-256k.bin"; > m->default_display = "std"; > m->no_floppy = 1; > + m->no_tco = 0; > m->alias = "q35"; > } > > @@ -404,6 +405,7 @@ static void pc_q35_2_3_machine_options(MachineClass > *m) > { > pc_q35_2_4_machine_options(m); > m->no_floppy = 0; > + m->no_tco = 1; > m->alias = NULL; > SET_MACHINE_COMPAT(m, PC_COMPAT_2_3); > } > diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c > index b3e0b1f..acf262c 100644 > --- a/hw/isa/lpc_ich9.c > +++ b/hw/isa/lpc_ich9.c > @@ -313,6 +313,16 @@ PCIINTxRoute ich9_route_intx_pin_to_irq(void *opaque, > int pirq_pin) > return route; > } > > +void ich9_generate_smi(void) > +{ > + cpu_interrupt(first_cpu, CPU_INTERRUPT_SMI); > +} > + > +void ich9_generate_nmi(void) > +{ > + cpu_interrupt(first_cpu, CPU_INTERRUPT_NMI); > +} > + > static int ich9_lpc_sci_irq(ICH9LPCState *lpc) > { > switch (lpc->d.config[ICH9_LPC_ACPI_CTRL] & > @@ -357,11 +367,12 @@ static void ich9_set_sci(void *opaque, int irq_num, > int level) > } > } > > -void ich9_lpc_pm_init(PCIDevice *lpc_pci) > +void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool enable_tco) > { > ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci); > > - ich9_pm_init(lpc_pci, &lpc->pm, qemu_allocate_irq(ich9_set_sci, lpc, > 0)); > + ich9_pm_init(lpc_pci, &lpc->pm, enable_tco, > + qemu_allocate_irq(ich9_set_sci, lpc, 0)); > ich9_lpc_reset(&lpc->d.qdev); > } > > diff --git a/include/hw/acpi/ich9.h b/include/hw/acpi/ich9.h > index 77cc65c..a7eb421 100644 > --- a/include/hw/acpi/ich9.h > +++ b/include/hw/acpi/ich9.h > @@ -25,6 +25,7 @@ > #include "hw/acpi/cpu_hotplug.h" > #include "hw/acpi/memory_hotplug.h" > #include "hw/acpi/acpi_dev_interface.h" > +#include "hw/acpi/tco.h" > > typedef struct ICH9LPCPMRegs { > /* > @@ -37,6 +38,7 @@ typedef struct ICH9LPCPMRegs { > MemoryRegion io; > MemoryRegion io_gpe; > MemoryRegion io_smi; > + MemoryRegion io_tco; > > uint32_t smi_en; > uint32_t smi_en_wmask; > @@ -54,9 +56,12 @@ typedef struct ICH9LPCPMRegs { > uint8_t disable_s3; > uint8_t disable_s4; > uint8_t s4_val; > + bool enable_tco; > + > + TCOIORegs tco_regs; > } ICH9LPCPMRegs; > > -void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, > +void ich9_pm_init(PCIDevice *lpc_pci, ICH9LPCPMRegs *pm, bool enable_tco, > qemu_irq sci_irq); > void ich9_pm_iospace_update(ICH9LPCPMRegs *pm, uint32_t pm_io_base); > extern const VMStateDescription vmstate_ich9_pm; > diff --git a/include/hw/acpi/tco.h b/include/hw/acpi/tco.h > new file mode 100644 > index 0000000..477a32c > --- /dev/null > +++ b/include/hw/acpi/tco.h > @@ -0,0 +1,98 @@ > +/* > + * QEMU ICH9 TCO emulation > + * > + * Copyright (c) 2015 Paulo Alcantara <pca...@zytor.com> > + * > + * Permission is hereby granted, free of charge, to any person obtaining > a copy > + * of this software and associated documentation files (the "Software"), > to deal > + * in the Software without restriction, including without limitation the > rights > + * to use, copy, modify, merge, publish, distribute, sublicense, and/or > sell > + * copies of the Software, and to permit persons to whom the Software is > + * furnished to do so, subject to the following conditions: > + * > + * The above copyright notice and this permission notice shall be > included in > + * all copies or substantial portions of the Software. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > EXPRESS OR > + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > MERCHANTABILITY, > + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT > SHALL > + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR > OTHER > + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, > ARISING FROM, > + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS > IN > + * THE SOFTWARE. > + */ > +#ifndef HW_ACPI_TCO_H > +#define HW_ACPI_TCO_H > + > +#include "qemu/typedefs.h" > +#include "qemu-common.h" > + > +/* As per ICH9 spec, the internal timer has an error of ~0.6s on every > tick */ > +#define TCO_TICK_NSEC 600000000LL > + > +/* TCO I/O register offsets */ > +enum { > + TCO_RLD = 0x00, > + TCO_DAT_IN = 0x02, > + TCO_DAT_OUT = 0x03, > + TCO1_STS = 0x04, > + TCO2_STS = 0x06, > + TCO1_CNT = 0x08, > + TCO2_CNT = 0x0a, > + TCO_MESSAGE1 = 0x0c, > + TCO_MESSAGE2 = 0x0d, > + TCO_WDCNT = 0x0e, > + SW_IRQ_GEN = 0x10, > + TCO_TMR = 0x12, > +}; > + > +/* TCO I/O register control/status bits */ > +enum { > + SW_TCO_SMI = 1 << 1, > + TCO_INT_STS = 1 << 2, > + TCO_LOCK = 1 << 12, > + TCO_TMR_HLT = 1 << 11, > + TCO_TIMEOUT = 1 << 3, > + TCO_SECOND_TO_STS = 1 << 1, > + TCO_BOOT_STS = 1 << 2, > +}; > + > +/* TCO I/O registers mask bits */ > +enum { > + TCO_RLD_MASK = 0x3ff, > + TCO1_STS_MASK = 0xe870, > + TCO2_STS_MASK = 0xfff8, > + TCO1_CNT_MASK = 0xfeff, > + TCO_TMR_MASK = 0x3ff, > +}; > + > +typedef struct TCOIORegs { > + bool use_tco;
This field is no longer used and should be removed. When I get home I'll send a v5 with this fix and the license stuff. Thank you all for reviewing it. That's really appreciable. Thanks, Paulo -- Paulo Alcantara, C.E.S.A.R Speaking for myself only.