kgpe: add patch for USE_WATCHDOG_ON_BOOT and enable it

This commit adds a coreboot patch which enables
CONFIG_USE_WATCHDOG_ON_BOOT for kgpe-d16; in upstream coreboot this
feature is found on only a few intel cpu platforms.

When enabled, this feature starts the hardware watchdog very early
in the boot process -- before PNP enumeration or DRAM
initialization.  This ensures that any hangs or freezes due to
transient conditions (flakiness, temperature, electrical noise)
won't prevent the machine from eventually booting.  This is very
useful for unattended servers.

On kgpe-d16 the watchdog is cancelled immediately before jumping to
the payload (i.e. Linux kernel).  I found that if I left the
watchdog enabled, any attempt to use it (for example, to cancel it
or extend it) from Linux resulted in the machine resetting.  Perhaps
this can be fixed, but for now I am content to simply re-enable the
watchdog from Linux rather than leaving it running.
master
Adam Joseph 1 year ago
parent c7c4370f18
commit 5ac11dd7fd

@ -109,6 +109,7 @@ stdenv.mkDerivation {
./patches/0004-superio-winbond-w83667hg-a-superio.c-do-not-use-get_.patch ./patches/0004-superio-winbond-w83667hg-a-superio.c-do-not-use-get_.patch
./patches/0001-romstage-print-out-dimm-voltages.patch ./patches/0001-romstage-print-out-dimm-voltages.patch
./patches/0002-kgpe-d16-do-not-enable-hw-monitor-until-kernel-boots.patch ./patches/0002-kgpe-d16-do-not-enable-hw-monitor-until-kernel-boots.patch
./patches/0026-kgpe-d16-start-w83667hg-a-watchdog-during-romstage.patch
# am1i patches # am1i patches
./patches/0021-am1i-omit-amdfw.rom-completely-it-has-broken-address.patch ./patches/0021-am1i-omit-amdfw.rom-completely-it-has-broken-address.patch

@ -0,0 +1,254 @@
From d320221a74a641712d97066d616b81df5a1fb3c1 Mon Sep 17 00:00:00 2001
From: Your Name <you@example.com>
Date: Sun, 11 Jun 2023 22:18:37 -0700
Subject: [PATCH] kgpe-d16: start w83667hg-a watchdog during romstage
---
src/mainboard/asus/kgpe-d16/Kconfig | 1 +
src/mainboard/asus/kgpe-d16/devicetree.cb | 2 +-
src/mainboard/asus/kgpe-d16/mainboard.c | 12 +++++
src/mainboard/asus/kgpe-d16/romstage.c | 12 +++++
src/superio/winbond/Makefile.inc | 1 +
src/superio/winbond/common/early_init.c | 53 ++++++++++++++++++++++-
src/superio/winbond/common/winbond.h | 1 +
src/superio/winbond/w83667hg-a/superio.c | 27 ++++++++++++
8 files changed, 106 insertions(+), 3 deletions(-)
diff --git a/src/mainboard/asus/kgpe-d16/Kconfig b/src/mainboard/asus/kgpe-d16/Kconfig
index c6b2de3ab92..3660b7c644b 100644
--- a/src/mainboard/asus/kgpe-d16/Kconfig
+++ b/src/mainboard/asus/kgpe-d16/Kconfig
@@ -32,6 +32,7 @@ config BOARD_SPECIFIC_OPTIONS
select DRIVERS_ASPEED_AST2050
select MAINBOARD_FORCE_NATIVE_VGA_INIT
select MAINBOARD_HAS_NATIVE_VGA_INIT
+ select USE_WATCHDOG_ON_BOOT
config MAINBOARD_DIR
string
diff --git a/src/mainboard/asus/kgpe-d16/devicetree.cb b/src/mainboard/asus/kgpe-d16/devicetree.cb
index ff2023ddd05..3be328d1725 100644
--- a/src/mainboard/asus/kgpe-d16/devicetree.cb
+++ b/src/mainboard/asus/kgpe-d16/devicetree.cb
@@ -199,7 +199,7 @@ chip northbridge/amd/amdfam10/root_complex # Root complex
device pnp 2e.207 off end # GIPO7
device pnp 2e.307 off end # GIPO8
device pnp 2e.407 off end # GIPO9
- device pnp 2e.8 off end # WDT
+ device pnp 2e.8 on end # WDT
device pnp 2e.108 off end # GPIO 1
device pnp 2e.9 off end # GPIO2
device pnp 2e.109 off end # GPIO3
diff --git a/src/mainboard/asus/kgpe-d16/mainboard.c b/src/mainboard/asus/kgpe-d16/mainboard.c
index 14a4a697620..8d377cafa95 100644
--- a/src/mainboard/asus/kgpe-d16/mainboard.c
+++ b/src/mainboard/asus/kgpe-d16/mainboard.c
@@ -21,8 +21,12 @@
#include <cpu/x86/msr.h>
#include <cpu/amd/mtrr.h>
#include <device/pci_def.h>
+#include <device/pnp.h>
#include <southbridge/amd/sb700/sb700.h>
#include <southbridge/amd/sr5650/cmn.h>
+#include <superio/winbond/common/winbond.h>
+#include <superio/winbond/w83667hg-a/w83667hg-a.h>
+#include <device/pnp_def.h>
void set_pcie_reset(void)
{
@@ -110,3 +114,11 @@ void sb7xx_51xx_setup_sata_port_indication(void *sata_bar5)
struct chip_operations mainboard_ops = {
.enable_dev = mainboard_enable,
};
+
+#define PNP_DEV(PORT, FUNC) (((PORT) << 8) | (FUNC))
+#define WDT_DEV PNP_DEV(0x2e, W83667HG_A_WDT1)
+#define ACPI_DEV PNP_DEV(0x2e, W83667HG_A_ACPI)
+void watchdog_off(void);
+void watchdog_off(void) {
+ winbond_enable_watchdog(WDT_DEV, ACPI_DEV, 0);
+}
diff --git a/src/mainboard/asus/kgpe-d16/romstage.c b/src/mainboard/asus/kgpe-d16/romstage.c
index 88fa60d2d1f..81a5bf5d67d 100644
--- a/src/mainboard/asus/kgpe-d16/romstage.c
+++ b/src/mainboard/asus/kgpe-d16/romstage.c
@@ -53,6 +53,8 @@
#define SERIAL_0_DEV PNP_DEV(0x2e, W83667HG_A_SP1)
#define SERIAL_1_DEV PNP_DEV(0x2e, W83667HG_A_SP2)
+#define WDT_DEV PNP_DEV(0x2e, W83667HG_A_WDT1)
+#define ACPI_DEV PNP_DEV(0x2e, W83667HG_A_ACPI)
void activate_spd_rom(const struct mem_controller *ctrl);
int spd_read_byte(unsigned int device, unsigned int address);
@@ -530,6 +532,8 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
byte = pci_read_config8(PCI_DEV(0, 0x14, 3), 0x78);
byte &= ~(1 << 0);
pci_write_config8(PCI_DEV(0, 0x14, 3), 0x78, byte);
+
+ winbond_enable_watchdog(WDT_DEV, ACPI_DEV, 40);
}
printk(BIOS_SPEW, "Initial stack pointer: %08x\n", esp);
@@ -681,6 +685,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
post_code(0x40);
+ if (!cpu_init_detectedx && boot_cpu()) {
+ winbond_enable_watchdog(WDT_DEV, ACPI_DEV, 60);
+ }
+ printk(BIOS_ERR, "initializing dram...\n");
timestamp_add_now(TS_BEFORE_INITRAM);
printk(BIOS_DEBUG, "raminit_amdmct()\n");
raminit_amdmct(sysinfo);
@@ -712,6 +720,10 @@ void cache_as_ram_main(unsigned long bist, unsigned long cpu_init_detectedx)
pci_write_config16(PCI_DEV(0, 0x14, 0), 0x54, 0x0707);
pci_write_config16(PCI_DEV(0, 0x14, 0), 0x56, 0x0bb0);
pci_write_config16(PCI_DEV(0, 0x14, 0), 0x5a, 0x0ff0);
+
+ if (!cpu_init_detectedx && boot_cpu()) {
+ winbond_enable_watchdog(WDT_DEV, ACPI_DEV, 60);
+ }
}
/**
diff --git a/src/superio/winbond/Makefile.inc b/src/superio/winbond/Makefile.inc
index b0b7b8c5202..0502441a2f0 100644
--- a/src/superio/winbond/Makefile.inc
+++ b/src/superio/winbond/Makefile.inc
@@ -15,6 +15,7 @@
## include generic winbond pre-ram stage driver
romstage-$(CONFIG_SUPERIO_WINBOND_COMMON_ROMSTAGE) += common/early_init.c
+ramstage-$(CONFIG_SUPERIO_WINBOND_COMMON_ROMSTAGE) += common/early_init.c
subdirs-y += w83627dhg
subdirs-y += w83627ehg
diff --git a/src/superio/winbond/common/early_init.c b/src/superio/winbond/common/early_init.c
index 7c3ce2b3a56..ba3cbb2a34f 100644
--- a/src/superio/winbond/common/early_init.c
+++ b/src/superio/winbond/common/early_init.c
@@ -33,9 +33,13 @@
*
*/
-#include <arch/io.h>
-#include <device/pnp.h>
+#define __SIMPLE_DEVICE__
+#include <arch/x86/include/arch/io.h>
+#include <device/pnp_def.h>
#include <stdint.h>
+#include <commonlib/stdlib.h>
+#include <commonlib/loglevel.h>
+#include <delay.h>
#include "winbond.h"
#define WINBOND_ENTRY_KEY 0x87
@@ -56,6 +60,51 @@ void pnp_exit_conf_state(pnp_devfn_t dev)
outb(WINBOND_EXIT_KEY, port);
}
+void winbond_enable_watchdog(pnp_devfn_t dev, pnp_devfn_t dev_acpi, u8 seconds)
+{
+#if IS_ENABLED(CONFIG_USE_WATCHDOG_ON_BOOT)
+ u8 byte;
+
+ // ACPI device: set EN_WDT2PWROK ////////////////////
+
+ pnp_enter_conf_state(dev_acpi);
+ pnp_set_logical_device(dev_acpi);
+ pnp_set_enable(dev_acpi, 1);
+ byte = pnp_read_config(dev_acpi, 0xf2);
+ byte |= (1<<7); // EN_WDT2PWROK = Enable PWROK0,1 or 2 pin drive pulse by WDTO
+ pnp_write_config(dev_acpi, 0xf2, byte);
+ pnp_exit_conf_state(dev_acpi);
+
+ // WDT device: enable timer ////////////////////
+
+ pnp_enter_conf_state(dev);
+ pnp_set_logical_device(dev);
+ pnp_set_enable(dev, 1);
+
+ byte = pnp_read_config(dev, 0xf5);
+ byte &= ~0x4e;
+ //byte |= 0x1 << 4; // count 1000 times faster than usual (i.e. milliseconds/milliminutes)
+ //byte |= 0x1 << 3; // count in minutes rather than seconds
+ byte |= 0x1 << 1; // Enable the WDTO# output low pulse to the KBRST# pin (PIN28)
+ pnp_write_config(dev, 0xf5, byte);
+
+ byte = pnp_read_config(dev, 0xf7);
+ byte &= ~0xc0; // keyboard/mouse interrupts do not reset WDT
+ pnp_write_config(dev, 0xf7, byte);
+
+ // watchdog timer value in seconds; countdown starts
+ // immediately.; write 0 to disable counter.
+ pnp_write_config(dev, 0xf6, seconds);
+
+ pnp_exit_conf_state(dev);
+ if (seconds == 0) {
+ printk(BIOS_ERR, "stopped W83667HG-A watchdog.\n");
+ } else {
+ printk(BIOS_ERR, "started W83667HG-A watchdog; you have %d seconds to disable it with: modprobe w83627hf_wdt; echo -n V > /dev/watchdog\n", seconds);
+ }
+#endif
+}
+
/* Bring up early serial debugging output before the RAM is initialized. */
void winbond_enable_serial(pnp_devfn_t dev, u16 iobase)
{
diff --git a/src/superio/winbond/common/winbond.h b/src/superio/winbond/common/winbond.h
index e472018bf19..87aa32ae46d 100644
--- a/src/superio/winbond/common/winbond.h
+++ b/src/superio/winbond/common/winbond.h
@@ -21,6 +21,7 @@
#include <stdint.h>
void winbond_enable_serial(pnp_devfn_t dev, uint16_t iobase);
+void winbond_enable_watchdog(pnp_devfn_t dev, pnp_devfn_t dev_acpi, u8 seconds);
void winbond_set_pinmux(pnp_devfn_t dev, uint8_t offset, uint8_t mask, uint8_t state);
void winbond_set_clksel_48(pnp_devfn_t dev);
diff --git a/src/superio/winbond/w83667hg-a/superio.c b/src/superio/winbond/w83667hg-a/superio.c
index ec1de699d0e..70794635293 100644
--- a/src/superio/winbond/w83667hg-a/superio.c
+++ b/src/superio/winbond/w83667hg-a/superio.c
@@ -81,9 +81,36 @@ static void w83667hg_a_init(struct device *dev)
else if (power_status == 2)
byte |= (0x2 << 5); /* Use last power state */
pnp_write_config(dev, 0xe4, byte);
+
+ byte = pnp_read_config(dev, 0xf2);
+ byte |= (1<<7); // EN_WDT2PWROK = Enable PWROK0,1 or 2 pin drive pulse by WDTO
+ pnp_write_config(dev, 0xf2, byte);
+
pnp_exit_conf_mode_aa(dev);
printk(BIOS_INFO, "set power %s after power fail\n", power_status ? "on" : "off");
break;
+ case W83667HG_A_WDT1:
+ pnp_enter_conf_mode_8787(dev);
+ pnp_set_logical_device(dev);
+
+ byte = pnp_read_config(dev, 0xf5);
+ byte &= ~0x4e;
+ //byte |= 0x1 << 1; // count 1000 times faster than usual (i.e. milliseconds/milliminutes)
+ //byte |= 0x1 << 1; // count in minutes rather than seconds
+ byte |= 0x1 << 1; // Enable the WDTO# output low pulse to the KBRST# pin (PIN28)
+ pnp_write_config(dev, 0xf5, byte);
+
+ byte = pnp_read_config(dev, 0xf7);
+ byte &= ~0xc0; // keyboard/mouse interrupts do not reset WDT
+ pnp_write_config(dev, 0xf7, byte);
+
+ // watchdog timer value in seconds; countdown starts
+ // immediately. write 0 to disable counter.
+ //pnp_write_config(dev, 0xf6, 0);
+ //printk(BIOS_INFO, "started watchdog timer!");
+
+ pnp_exit_conf_mode_aa(dev);
+ break;
}
}
--
2.39.1

@ -97,6 +97,14 @@
CONSOLE_CBMEM = lib.mkForce no; CONSOLE_CBMEM = lib.mkForce no;
ONBOARD_VGA_IS_PRIMARY = lib.mkForce no; ONBOARD_VGA_IS_PRIMARY = lib.mkForce no;
# Coreboot on some versions of the kgpe-d16 will hang during
# PNP enumeration approximately ~10% of the time during PNP
# enumeration (before DRAM init); starting the watchdog from
# the romstage ensures that the machine will always finish
# booting, although it may take two (or in rare cases three)
# attempts. You absolutely want this for unattended servers.
USE_WATCHDOG_ON_BOOT = lib.mkForce yes;
}; };
coreboot-toolchain = with final.coreboot-toolchain; [ x64 i386 ]; coreboot-toolchain = with final.coreboot-toolchain; [ x64 i386 ];
uart-for-console = uart-for-console =

Loading…
Cancel
Save