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 pcacjr@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 pcacjr@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
*/
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,
ich9_lpc_reset(&lpc->d.qdev);qemu_allocate_irq(ich9_set_sci, lpc, 0));
}
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 pcacjr@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