Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F145401086
D52049.id160679.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
8 KB
Referenced Files
None
Subscribers
None
D52049.id160679.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D52049: ichwd: introduce i6300esb watch dog driver
Attached
Detach File
Event Timeline
Log In to Comment