Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 29 Apr 2007 01:49:10 +0900
From:      Takeharu KATO <takeharu1219@ybb.ne.jp>
To:        freebsd-arch@freebsd.org
Subject:   ichwd for ICH8 
Message-ID:  <46337B06.9080102@ybb.ne.jp>

next in thread | raw e-mail | index | archive | help
Hi,

I am trying to port ichwd to ICH6 and later.
I have a box which has ICH8 compliant mother board(GIGA BYTE GA-965P-DS3).

As far as I refer the manual(Intel I/O Controller Hub 8 (ICH8)
Family) , this driver can setup counter properly and then
enable watchdog facility.

But the driver can not make the system reboot when watchdog fire
the interrupt.

I can not figure out the reason of this problem is caused by
my patch or current ichwd part.
Because I do not have the box which have ICH5 or before.

Does anyone use ichwd?


diff -Nupr ichwd.orig/ichwd.c ichwd/ichwd.c
--- ichwd.orig/ichwd.c	Wed Apr 25 22:03:16 2007
+++ ichwd/ichwd.c	Fri Apr 27 00:59:16 2007
@@ -71,20 +71,27 @@ __FBSDID("$FreeBSD: src/sys/dev/ichwd/ic
 #include <dev/ichwd/ichwd.h>

 static struct ichwd_device ichwd_devices[] = {
-	{ VENDORID_INTEL, DEVICEID_82801AA, "Intel 82801AA watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801AB, "Intel 82801AB watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801BA, "Intel 82801BA watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801BAM, "Intel 82801BAM watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801CA, "Intel 82801CA watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801CAM, "Intel 82801CAM watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801DB, "Intel 82801DB watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801DBM, "Intel 82801DBM watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801E, "Intel 82801E watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801EBR, "Intel 82801EB/ER watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_82801FBR, "Intel 82801FB/FR watchdog timer" },
-	{ VENDORID_INTEL, DEVICEID_ICH5, "Intel ICH5 watchdog timer"},
-	{ VENDORID_INTEL, DEVICEID_6300ESB, "Intel 6300ESB watchdog timer"},
-	{ 0, 0, NULL },
+	{ VENDORID_INTEL, DEVICEID_82801AA,  "Intel 82801AA watchdog timer",
  1} ,
+	{ VENDORID_INTEL, DEVICEID_82801AB,  "Intel 82801AB watchdog timer",
  1} ,
+	{ VENDORID_INTEL, DEVICEID_82801BA,  "Intel 82801BA watchdog timer",
  1} ,
+	{ VENDORID_INTEL, DEVICEID_82801BAM, "Intel 82801BAM watchdog timer",
  1} ,
+	{ VENDORID_INTEL, DEVICEID_82801CA,  "Intel 82801CA watchdog timer",
  1} ,
+	{ VENDORID_INTEL, DEVICEID_82801CAM, "Intel 82801CAM watchdog timer",
  1} ,
+	{ VENDORID_INTEL, DEVICEID_82801DB,  "Intel 82801DB watchdog timer",
  1} ,
+	{ VENDORID_INTEL, DEVICEID_82801DBM, "Intel 82801DBM watchdog timer",
  1} ,
+	{ VENDORID_INTEL, DEVICEID_82801E,   "Intel 82801E watchdog timer",
  1} ,
+	{ VENDORID_INTEL, DEVICEID_82801EBR, "Intel 82801EB/ER watchdog
timer", 1} ,
+	{ VENDORID_INTEL, DEVICEID_82801FBR, "Intel 82801FB/FR watchdog
timer", 2} ,
+	{ VENDORID_INTEL, DEVICEID_ICH5,     "Intel ICH5 watchdog timer",
  2} ,
+	{ VENDORID_INTEL, DEVICEID_6300ESB,  "Intel 6300ESB watchdog timer",
  2} ,
+	{ VENDORID_INTEL, DEVICEID_ICH6M,    "Intel ICH6M watchdog timer",
  2} ,
+	{ VENDORID_INTEL, DEVICEID_ICH6W,    "Intel ICH6W watchdog timer",
  2} ,
+	{ VENDORID_INTEL, DEVICEID_ICH7M,    "Intel ICH7M watchdog timer",
  2} ,
+	{ VENDORID_INTEL, DEVICEID_ICH7MDH,  "Intel ICH7MDH watchdog timer",
  2} ,
+	{ VENDORID_INTEL, DEVICEID_ICH8,     "Intel ICH8 watchdog timer",
  2} ,
+	{ VENDORID_INTEL, DEVICEID_ICH8DH,   "Intel ICH8DH watchdog timer",
  2} ,
+	{ VENDORID_INTEL, DEVICEID_ICH8DO,   "Intel ICH8DO watchdog timer",
  2} ,
+	{ 0, 0, NULL, 0 } ,
 };

 static devclass_t ichwd_devclass;
@@ -103,11 +110,21 @@ static devclass_t ichwd_devclass;
 #define ichwd_write_tco_4(sc, off, val) \
 	bus_space_write_4((sc)->tco_bst, (sc)->tco_bsh, (off), (val))

-#define ichwd_read_smi_4(sc, off) \
+#define ichwd_read_smi_4(sc, off)       \
 	bus_space_read_4((sc)->smi_bst, (sc)->smi_bsh, (off))
 #define ichwd_write_smi_4(sc, off, val) \
 	bus_space_write_4((sc)->smi_bst, (sc)->smi_bsh, (off), (val))

+#define ichwd_read_gcs_4(sc, off)       \
+	bus_read_4((sc)->gcs_res, (off))
+#define ichwd_write_gcs_4(sc, off, val) \
+	bus_write_4((sc)->gcs_res, (off), (val))
+
+#define ichwd_verbose_printf(dev,fmt,arg...) do {	\
+		if (bootverbose)			\
+			device_printf(dev, fmt, ##arg);	\
+	} while (0)
+
 static __inline void
 ichwd_intr_enable(struct ichwd_softc *sc)
 {
@@ -136,8 +153,7 @@ ichwd_tmr_enable(struct ichwd_softc *sc)
 	cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE;
 	ichwd_write_tco_2(sc, TCO1_CNT, cnt & ~TCO_TMR_HALT);
 	sc->active = 1;
-	if (bootverbose)
-		device_printf(sc->device, "timer enabled\n");
+	ichwd_verbose_printf(sc->device, "timer enabled\n");
 }

 static __inline void
@@ -148,25 +164,67 @@ ichwd_tmr_disable(struct ichwd_softc *sc
 	cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE;
 	ichwd_write_tco_2(sc, TCO1_CNT, cnt | TCO_TMR_HALT);
 	sc->active = 0;
-	if (bootverbose)
-		device_printf(sc->device, "timer disabled\n");
+	ichwd_verbose_printf(sc->device, "timer disabled\n");
 }

 static __inline void
 ichwd_tmr_reload(struct ichwd_softc *sc)
 {
-	ichwd_write_tco_1(sc, TCO_RLD, 1);
-	if (bootverbose)
-		device_printf(sc->device, "timer reloaded\n");
+	if (sc->tco_version == 1)
+		ichwd_write_tco_1(sc, TCO_RLD, 1);
+	else
+		ichwd_write_tco_2(sc, TCO_RLD, 1);
+
+	ichwd_verbose_printf(sc->device, "timer reloaded\n");
 }

 static __inline void
 ichwd_tmr_set(struct ichwd_softc *sc, uint8_t timeout)
 {
-	ichwd_write_tco_1(sc, TCO_TMR, timeout);
+
+	if (sc->tco_version == 1) {
+		ichwd_write_tco_1(sc, TCO_TMR, timeout);
+	} else {
+		uint16_t tmr_val = ichwd_read_tco_2(sc, TCO_V2_TMR);
+
+		tmr_val &= 0xfc00;
+		tmr_val |= timeout;
+		ichwd_write_tco_2(sc, TCO_V2_TMR, tmr_val);
+	}
+
 	sc->timeout = timeout;
-	if (bootverbose)
-		device_printf(sc->device, "timeout set to %u ticks\n", timeout);
+
+	ichwd_verbose_printf(sc->device, "timeout set to %u ticks\n", timeout);
+}
+
+static __inline int
+ichwd_clear_noreboot(struct ichwd_softc *sc)
+{
+	uint32_t	status;
+	int		rc = 0;
+
+	/* try to clear the NO_REBOOT bit */
+	if (sc->tco_version == 1) {
+		pci_write_config(sc->ich, ICH_GEN_STA, 0x00, 1);
+		status = pci_read_config(sc->ich, ICH_GEN_STA, 1);
+		if (status & ICH_GEN_STA_NO_REBOOT)
+			rc = EIO;
+	} else {
+	     status = ichwd_read_gcs_4(sc, 0);
+	     status &= ~(GCS_NOREBOOT);
+	     ichwd_write_gcs_4(sc, 0, status);
+
+	     status = ichwd_read_gcs_4(sc, 0);
+	     if (status & GCS_NOREBOOT)
+		     rc = EIO;
+	}
+
+	if (rc)
+		ichwd_verbose_printf(sc->device,
+				     "%s(): ICH WDT present but disabled\n",
+				     __func__);
+
+	return rc;
 }

 /*
@@ -197,7 +255,24 @@ ichwd_event(void *arg, unsigned int cmd,
 	}
 }

-static unsigned int pmbase = 0;
+static device_t
+ichwd_find_ich_lpc_bridge(struct ichwd_device **id_p) {
+	struct ichwd_device *id;
+	device_t ich = NULL;
+
+        /* look for an ICH LPC interface bridge */
+	for (id = ichwd_devices; id->desc != NULL; ++id)
+		if ((ich = pci_find_device(id->vendor, id->device)) != NULL)
+			break;
+
+	if ( (bootverbose) && (ich) )
+		printf("%s(): found ICH chipset: %s TCO version:%d\n", __func__,
id->desc, id->version);
+
+	if (id_p)
+		*id_p = id;
+
+	return ich;
+}

 /*
  * Look for an ICH LPC interface bridge.  If one is found, register an
@@ -206,44 +281,33 @@ static unsigned int pmbase = 0;
 static void
 ichwd_identify(driver_t *driver, device_t parent)
 {
-	struct ichwd_device *id;
+	struct ichwd_device *id_p;
 	device_t ich = NULL;
 	device_t dev;
+	uint32_t rcba;
+	int rc;

-	/* look for an ICH LPC interface bridge */
-	for (id = ichwd_devices; id->desc != NULL; ++id)
-		if ((ich = pci_find_device(id->vendor, id->device)) != NULL)
-			break;
+	ich = ichwd_find_ich_lpc_bridge(&id_p);
 	if (ich == NULL)
 		return;

-	if (bootverbose)
-		printf("%s(): found ICH chipset: %s\n", __func__, id->desc);
-
-	/* get for ACPI base address */
-	pmbase = pci_read_config(ich, ICH_PMBASE, 2) & ICH_PMBASE_MASK;
-	if (pmbase == 0) {
-		if (bootverbose)
-			printf("%s(): ICH PMBASE register is empty\n",
-			    __func__);
-		return;
-	}
-
-	/* try to clear the NO_REBOOT bit */
-	pci_write_config(ich, ICH_GEN_STA, 0x00, 1);
-	if (pci_read_config(ich, ICH_GEN_STA, 1) & ICH_GEN_STA_NO_REBOOT) {
-		if (bootverbose)
-			printf("%s(): ICH WDT present but disabled\n",
-			    __func__);
-		return;
-	}
-
 	/* good, add child to bus */
 	if ((dev = device_find_child(parent, driver->name, 0)) == NULL)
 		dev = BUS_ADD_CHILD(parent, 0, driver->name, 0);

-	if (dev != NULL)
-		device_set_desc_copy(dev, id->desc);
+	if (dev != NULL) {
+		device_set_desc_copy(dev, id_p->desc);
+
+		if (id_p->version == 2) {
+			/* set rcba */
+			rcba = (pci_read_config(ich, ICH_RCBA, 4) & (0xffffc000));
+			rc = bus_set_resource(ich, SYS_RES_MEMORY, 0, rcba, ICH_GCS_SIZE);
+			if (rc)
+				ichwd_verbose_printf(dev, "%s(): Can not set memory
resource:0x%x\n", __func__, rcba);
+			else
+				ichwd_verbose_printf(dev, "%s(): This machine has TCO Version 2
wdt.\n", __func__);
+		}
+	}
 }

 static int
@@ -257,12 +321,27 @@ static int
 ichwd_attach(device_t dev)
 {
 	struct ichwd_softc *sc;
+	struct ichwd_device *id_p;
+	device_t ich;
+	unsigned int pmbase = 0;

 	sc = device_get_softc(dev);
 	sc->device = dev;

+	ich = ichwd_find_ich_lpc_bridge(&id_p);
+	if (ich == NULL) {
+		device_printf(sc->device, "Can not find ICH device.\n");
+		goto fail;
+	}
+	sc->ich = ich;
+	sc->tco_version = id_p->version;
+
+	/* get for ACPI base address */
+	pmbase = pci_read_config(ich, ICH_PMBASE, 2) & ICH_PMBASE_MASK;
 	if (pmbase == 0) {
-		printf("Not found\n");
+		ichwd_verbose_printf(sc->device, "%s(): ICH PMBASE register is empty\n",
+			    __func__);
+		goto fail;
 	}

 	/* allocate I/O register space */
@@ -287,6 +366,21 @@ ichwd_attach(device_t dev)
 	}
 	sc->tco_bst = rman_get_bustag(sc->tco_res);
 	sc->tco_bsh = rman_get_bushandle(sc->tco_res);
+
+	sc->gcs_rid = 0;
+	sc->gcs_res = bus_alloc_resource_any(ich, SYS_RES_MEMORY, &sc->gcs_rid,
+					     RF_ACTIVE|RF_SHAREABLE);
+	if ( (sc->gcs_res == NULL) && (sc->tco_version != 1) ) {
+		device_printf(dev, "unable to reserve GCS registers\n");
+		goto fail;
+	}
+
+	if (ichwd_clear_noreboot(sc))
+		goto fail;
+
+	device_printf(dev, "%s (TCO version %d)\n",
+		      device_get_desc(dev), sc->tco_version);
+
 	/* reset the watchdog status registers */

 	ichwd_sts_reset(sc);
@@ -309,6 +403,10 @@ ichwd_attach(device_t dev)
 	if (sc->smi_res != NULL)
 		bus_release_resource(dev, SYS_RES_IOPORT,
 		    sc->smi_rid, sc->smi_res);
+	if (sc->gcs_res != NULL)
+		bus_release_resource(ich, SYS_RES_MEMORY,
+		    sc->gcs_rid, sc->gcs_res);
+
 	return (ENXIO);
 }

@@ -316,6 +414,7 @@ static int
 ichwd_detach(device_t dev)
 {
 	struct ichwd_softc *sc;
+	device_t ich = NULL;

 	sc = device_get_softc(dev);

@@ -338,6 +437,10 @@ ichwd_detach(device_t dev)
 	bus_release_resource(dev, SYS_RES_IOPORT, sc->tco_rid, sc->tco_res);
 	bus_release_resource(dev, SYS_RES_IOPORT, sc->smi_rid, sc->smi_res);

+	/* deallocate memory resource */
+	ich = ichwd_find_ich_lpc_bridge(NULL);
+	if ( (sc->gcs_res) && (ich) )
+		bus_release_resource(ich, SYS_RES_MEMORY, sc->gcs_rid, sc->gcs_res);
 	return (0);
 }

diff -Nupr ichwd.orig/ichwd.h ichwd/ichwd.h
--- ichwd.orig/ichwd.h	Wed Apr 25 22:03:16 2007
+++ ichwd/ichwd.h	Fri Apr 27 01:03:54 2007
@@ -35,11 +35,12 @@ struct ichwd_device {
 	uint16_t		 vendor;
 	uint16_t		 device;
 	char			*desc;
+	unsigned int	version;
 };

 struct ichwd_softc {
 	device_t		 device;
-
+	device_t 		 ich;
 	int			 active;
 	unsigned int		 timeout;

@@ -53,6 +54,11 @@ struct ichwd_softc {
 	bus_space_tag_t		 tco_bst;
 	bus_space_handle_t	 tco_bsh;

+	int			 gcs_rid;
+	struct resource		*gcs_res;
+
+	int                      tco_version;
+
 	eventhandler_tag	 ev_tag;
 };

@@ -70,6 +76,13 @@ struct ichwd_softc {
 #define DEVICEID_6300ESB	0x25a1
 #define DEVICEID_82801FBR	0x2640
 #define DEVICEID_ICH5		0x27b8
+#define DEVICEID_ICH6M		0x2641
+#define DEVICEID_ICH6W		0x2642
+#define DEVICEID_ICH7M		0x27b9
+#define DEVICEID_ICH7MDH	0x27bd
+#define DEVICEID_ICH8		0x2810
+#define DEVICEID_ICH8DH		0x2812
+#define DEVICEID_ICH8DO		0x2814

 /* ICH LPC Interface Bridge Registers */
 #define ICH_GEN_STA		0xd4
@@ -111,6 +124,12 @@ struct ichwd_softc {
 /* control bits for TCO1_CNT */
 #define TCO_TMR_HALT		0x0800 /* clear to enable WDT */
 #define TCO_CNT_PRESERVE	0x0200 /* preserve these bits */
+
+#define ICH_RCBA		0xf0
+#define ICH_GCS_OFFSET		0x3410
+#define ICH_GCS_SIZE		0x4
+#define GCS_NOREBOOT		0x00000020
+#define TCO_V2_TMR		0x12 /* TCO Timer Initial Value for V2 */

 /* approximate length in nanoseconds of one WDT tick */
 #define ICHWD_TICK		1800000000





Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?46337B06.9080102>