summaryrefslogtreecommitdiff
path: root/hw/isa/lpc_ich9.c
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@gmail.com>2015-06-28 14:58:56 -0300
committerMichael S. Tsirkin <mst@redhat.com>2015-07-07 13:12:22 +0300
commit920557971b60e53c2f3f22e5d6c620ab1ed411fd (patch)
tree5630d4b1c74b28ba22273d5980ecedcbe367fa38 /hw/isa/lpc_ich9.c
parent71ba2f0af398f616e154137d9fdda25c2da01324 (diff)
downloadqemu-920557971b60e53c2f3f22e5d6c620ab1ed411fd.tar.gz
ich9: add TCO interface emulation
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> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
Diffstat (limited to 'hw/isa/lpc_ich9.c')
-rw-r--r--hw/isa/lpc_ich9.c15
1 files changed, 13 insertions, 2 deletions
diff --git a/hw/isa/lpc_ich9.c b/hw/isa/lpc_ich9.c
index bd655b8405..7af24fa8eb 100644
--- a/hw/isa/lpc_ich9.c
+++ b/hw/isa/lpc_ich9.c
@@ -138,6 +138,7 @@ static void ich9_cc_reset(ICH9LPCState *lpc)
pci_set_long(c + ICH9_CC_D27IR, ICH9_CC_DIR_DEFAULT);
pci_set_long(c + ICH9_CC_D26IR, ICH9_CC_DIR_DEFAULT);
pci_set_long(c + ICH9_CC_D25IR, ICH9_CC_DIR_DEFAULT);
+ pci_set_long(c + ICH9_CC_GCS, ICH9_CC_GCS_DEFAULT);
ich9_cc_update(lpc);
}
@@ -313,6 +314,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,13 +368,13 @@ static void ich9_set_sci(void *opaque, int irq_num, int level)
}
}
-void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled)
+void ich9_lpc_pm_init(PCIDevice *lpc_pci, bool smm_enabled, bool enable_tco)
{
ICH9LPCState *lpc = ICH9_LPC_DEVICE(lpc_pci);
qemu_irq sci_irq;
sci_irq = qemu_allocate_irq(ich9_set_sci, lpc, 0);
- ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, sci_irq);
+ ich9_pm_init(lpc_pci, &lpc->pm, smm_enabled, enable_tco, sci_irq);
ich9_lpc_reset(&lpc->d.qdev);
}