Page MenuHomeFreeBSD

D52049.id160679.diff
No OneTemporary

D52049.id160679.diff

diff --git a/sys/dev/ichwd/i6300esb.h b/sys/dev/ichwd/i6300esb.h
new file mode 100644
--- /dev/null
+++ b/sys/dev/ichwd/i6300esb.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2025 ShengYi Hung <aokblast@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#ifndef _I6300WD_H_
+#define _I6300WD_H_
+
+#define WDT_CONFIG_REG 0x60
+#define WDT_LOCK_REG 0x68
+
+#define WDT_PRELOAD_1_REG 0x00
+#define WDT_PRELOAD_2_REG 0x04
+#define WDT_INTR_REG 0x08
+#define WDT_RELOAD_REG 0x0
+
+/* For config register */
+#define WDT_OUTPUT_EN (0x1 << 5)
+#define WDT_PRE_SEL (0x1 << 2)
+#define WDT_INT_TYPE_BITS (0x3)
+#define WDT_INT_TYPE_IRQ_VAL (0x0)
+#define WDT_INT_TYPE_RES_VAL (0x1)
+#define WDT_INT_TYPE_SMI_VAL (0x2)
+#define WDT_INT_TYPE_DISABLED_VAL (0x3)
+
+/* For lock register */
+#define WDT_TOUT_CNF_WT_MODE (0x0 << 2)
+#define WDT_TOUT_CNF_FR_MODE (0x1 << 2)
+#define WDT_ENABLE (0x02)
+#define WDT_LOCK (0x01)
+
+/* For preload 1/2 registers */
+#define WDT_PRELOAD_BIT 20
+#define WDT_PRELOAD_BITS ((0x1 << WDT_PRELOAD_BIT) - 1)
+
+/* For interrupt register */
+#define WDT_INTR_ACT (0x01 << 0)
+
+/* For reload register */
+#define WDT_TIMEOUT (0x01 << 9)
+#define WDT_RELOAD (0x01 << 8)
+#define WDT_UNLOCK_SEQ_1_VAL 0x80
+#define WDT_UNLOCK_SEQ_2_VAL 0x86
+
+#endif //_I6300WD_H_
diff --git a/sys/dev/ichwd/i6300esb.c b/sys/dev/ichwd/i6300esb.c
new file mode 100644
--- /dev/null
+++ b/sys/dev/ichwd/i6300esb.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2025 ShengYi Hung <aokblast@FreeBSD.org>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+/*
+ * Reference: Intel 6300ESB Controller Hub Datasheet Section 16
+ */
+
+#include <sys/param.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <machine/bus.h>
+#include <sys/rman.h>
+#include <machine/resource.h>
+#include <sys/watchdog.h>
+
+#include <isa/isavar.h>
+#include <dev/pci/pcireg.h>
+
+#include <dev/ichwd/ichwd.h>
+#include <dev/ichwd/i6300esb.h>
+
+#include <x86/pci_cfgreg.h>
+#include <dev/pci/pcivar.h>
+#include <dev/pci/pci_private.h>
+
+#define PCI_VENDOR_INTEL 0x8086
+
+static int i6300esb_locked;
+static int i6300esb_scale;
+static int i6300esb_reboot;
+static SYSCTL_NODE(_hw, OID_AUTO, i6300esb, CTLFLAG_RW, 0, "i6300esb");
+SYSCTL_INT(_hw_i6300esb, OID_AUTO, locked, CTLFLAG_RWTUN, &i6300esb_locked, 1,
+ "Lock enable status forever");
+SYSCTL_INT(_hw_i6300esb, OID_AUTO, scale, CTLFLAG_RDTUN, &i6300esb_scale, 1,
+ "Scale the i6300esb from 1khz to 1mhz");
+SYSCTL_INT(_hw_i6300esb, OID_AUTO, reboot, CTLFLAG_RDTUN, &i6300esb_reboot, 1,
+ "Reboot when timeout");
+
+struct i6300esb_softc {
+ device_t dev;
+ int res_id;
+ struct resource *res;
+ eventhandler_tag ev_tag;
+ bool locked;
+};
+
+static struct i6300esb_pci_id {
+ uint16_t id;
+ char *name;
+} i6300esb_pci_devices[] = {
+ { DEVICEID_6300ESB_5, "6300ESB Watchdog Timer" },
+};
+
+static uint16_t
+i6300esb_cfg_read(struct i6300esb_softc *sc)
+{
+ return (pci_read_config(sc->dev, WDT_CONFIG_REG, 2));
+}
+
+static void
+i6300esb_cfg_write(struct i6300esb_softc *sc, uint16_t val)
+{
+ pci_write_config(sc->dev, WDT_CONFIG_REG, val, 2);
+}
+
+static uint8_t
+i6300esb_lock_read(struct i6300esb_softc *sc)
+{
+ return (pci_read_config(sc->dev, WDT_LOCK_REG, 1));
+}
+
+static void
+i6300esb_lock_write(struct i6300esb_softc *sc, uint8_t val)
+{
+ pci_write_config(sc->dev, WDT_LOCK_REG, val, 1);
+}
+
+/*
+ * According to Intel Intel® 6300ESB I/O Controller Hub Datasheet 16.5.2
+ * The resource should be unlock before you modify any value to the bus resource
+ * The way to unlock is by write 0x80, 0x86 to the reload register.
+ */
+static void
+i6300esb_unlock_res(struct i6300esb_softc *sc)
+{
+ bus_write_2(sc->res, WDT_RELOAD_REG, WDT_UNLOCK_SEQ_1_VAL);
+ bus_write_2(sc->res, WDT_RELOAD_REG, WDT_UNLOCK_SEQ_2_VAL);
+}
+
+static void
+i6300esb_event(void *arg, unsigned int cmd, int *error)
+{
+ struct i6300esb_softc *sc = arg;
+ uint32_t timeout;
+ uint16_t regval;
+ int ticks;
+
+ if (i6300esb_scale)
+ ticks = WD_TO_1US;
+ else
+ ticks = WD_TO_1MS;
+
+ cmd &= WD_INTERVAL;
+ if (cmd != 0 && (cmd < ticks || (cmd - ticks) > WDT_PRELOAD_BIT)) {
+ *error = EINVAL;
+ return;
+ }
+ timeout = 1 << (cmd - ticks);
+
+ /* reset the timer to prevent timeout a timeout is about to occur */
+ i6300esb_unlock_res(sc);
+ bus_write_2(sc->res, WDT_RELOAD_REG, WDT_RELOAD);
+
+ if (!cmd) {
+ /*
+ * when the lock is enabled, we are unable to overwrite LOCK
+ * register
+ */
+ if (sc->locked) {
+ *error = EPERM;
+ }
+ i6300esb_lock_write(sc, i6300esb_lock_read(sc) & ~(WDT_ENABLE));
+ return;
+ }
+
+ i6300esb_unlock_res(sc);
+ bus_write_4(sc->res, WDT_PRELOAD_1_REG, timeout);
+
+ i6300esb_unlock_res(sc);
+ bus_write_4(sc->res, WDT_PRELOAD_2_REG, timeout);
+
+ i6300esb_unlock_res(sc);
+ bus_write_2(sc->res, WDT_RELOAD_REG, WDT_RELOAD);
+
+ if (!sc->locked) {
+ i6300esb_lock_write(sc,
+ WDT_ENABLE | (i6300esb_locked ? WDT_LOCK : 0));
+ regval = i6300esb_lock_read(sc);
+ sc->locked = regval & WDT_LOCK;
+ }
+ return;
+}
+
+static int
+i6300esb_probe(device_t dev)
+{
+ static struct i6300esb_pci_id *pci_id;
+ uint16_t pci_dev_id;
+ int err = ENXIO;
+
+ if (pci_get_vendor(dev) != PCI_VENDOR_INTEL)
+ goto end;
+
+ pci_dev_id = pci_get_device(dev);
+ for (pci_id = i6300esb_pci_devices;
+ pci_id < i6300esb_pci_devices + sizeof(i6300esb_pci_devices);
+ ++pci_id) {
+ if (pci_id->id == pci_dev_id) {
+ device_set_desc(dev, pci_id->name);
+ err = BUS_PROBE_DEFAULT;
+ goto end;
+ }
+ }
+
+end:
+ return (err);
+}
+
+static int
+i6300esb_attach(device_t dev)
+{
+ struct i6300esb_softc *sc = device_get_softc(dev);
+ uint16_t regval;
+
+ sc->dev = dev;
+ sc->res_id = PCIR_BAR(0);
+ sc->res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->res_id,
+ RF_ACTIVE);
+ if (sc->res == NULL) {
+ device_printf(dev, "unable to map memory region\n");
+ return (ENXIO);
+ }
+
+ i6300esb_cfg_write(sc,
+ WDT_INT_TYPE_DISABLED_VAL | (i6300esb_scale ? WDT_PRE_SEL : 0) |
+ (i6300esb_reboot ? WDT_OUTPUT_EN : 0));
+ regval = i6300esb_lock_read(sc);
+ if (regval & WDT_LOCK)
+ sc->locked = true;
+ i6300esb_lock_write(sc, WDT_TOUT_CNF_WT_MODE);
+
+ i6300esb_unlock_res(sc);
+ bus_write_2(sc->res, WDT_RELOAD_REG, WDT_RELOAD | WDT_TIMEOUT);
+
+ sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, i6300esb_event, sc,
+ 0);
+
+ return (0);
+}
+
+static int
+i6300esb_detach(device_t dev)
+{
+ struct i6300esb_softc *sc = device_get_softc(dev);
+
+ if (sc->ev_tag)
+ EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag);
+
+ if (sc->res)
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->res_id, sc->res);
+
+ return (0);
+}
+
+static device_method_t i6300esb_methods[] = {
+ DEVMETHOD(device_probe, i6300esb_probe),
+ DEVMETHOD(device_attach, i6300esb_attach),
+ DEVMETHOD(device_detach, i6300esb_detach),
+ DEVMETHOD(device_shutdown, i6300esb_detach),
+ { 0, 0 }
+};
+
+static driver_t i6300esb_driver = {
+ "i6300esb",
+ i6300esb_methods,
+ sizeof(struct i6300esb_softc),
+};
+
+DRIVER_MODULE(i6300esb, pci, i6300esb_driver, NULL, NULL);
diff --git a/sys/dev/ichwd/ichwd.h b/sys/dev/ichwd/ichwd.h
--- a/sys/dev/ichwd/ichwd.h
+++ b/sys/dev/ichwd/ichwd.h
@@ -151,7 +151,12 @@
#define DEVICEID_82801E 0x2450
#define DEVICEID_82801EB 0x24dc
#define DEVICEID_82801EBR 0x24d0
-#define DEVICEID_6300ESB 0x25a1
+#define DEVICEID_6300ESB_1 0x25a1
+#define DEVICEID_6300ESB_2 0x25a2
+#define DEVICEID_6300ESB_3 0x25a4
+#define DEVICEID_6300ESB_4 0x25a6
+#define DEVICEID_6300ESB_5 0x25ab
+#define DEVICEID_6300ESB_6 0x25ac
#define DEVICEID_82801FBR 0x2640
#define DEVICEID_ICH6M 0x2641
#define DEVICEID_ICH6W 0x2642
diff --git a/sys/dev/ichwd/ichwd.c b/sys/dev/ichwd/ichwd.c
--- a/sys/dev/ichwd/ichwd.c
+++ b/sys/dev/ichwd/ichwd.c
@@ -90,7 +90,7 @@
{ DEVICEID_82801E, "Intel 82801E watchdog timer", 5, 1 },
{ DEVICEID_82801EB, "Intel 82801EB watchdog timer", 5, 1 },
{ DEVICEID_82801EBR, "Intel 82801EB/ER watchdog timer", 5, 1 },
- { DEVICEID_6300ESB, "Intel 6300ESB watchdog timer", 5, 1 },
+ { DEVICEID_6300ESB_1, "Intel 6300ESB watchdog timer", 5, 1 },
{ DEVICEID_82801FBR, "Intel 82801FB/FR watchdog timer", 6, 2 },
{ DEVICEID_ICH6M, "Intel ICH6M watchdog timer", 6, 2 },
{ DEVICEID_ICH6W, "Intel ICH6W watchdog timer", 6, 2 },
diff --git a/sys/modules/i6300esb/Makefile b/sys/modules/i6300esb/Makefile
new file mode 100644
--- /dev/null
+++ b/sys/modules/i6300esb/Makefile
@@ -0,0 +1,6 @@
+.PATH: ${SRCTOP}/sys/dev/ichwd
+
+KMOD= i6300esb
+SRCS= i6300esb.c device_if.h bus_if.h pci_if.h isa_if.h
+
+.include <bsd.kmod.mk>
diff --git a/sys/sys/watchdog.h b/sys/sys/watchdog.h
--- a/sys/sys/watchdog.h
+++ b/sys/sys/watchdog.h
@@ -83,6 +83,7 @@
/* Handy macros for humans not used to power of two nanoseconds */
#define WD_TO_NEVER 0
+#define WD_TO_1US 10
#define WD_TO_1MS 20
#define WD_TO_125MS 27
#define WD_TO_250MS 28

File Metadata

Mime Type
text/plain
Expires
Fri, Feb 20, 9:07 AM (15 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28896926
Default Alt Text
D52049.id160679.diff (8 KB)

Event Timeline