ichwd.c revision 199015
1/*-
2 * Copyright (c) 2004 Texas A&M University
3 * All rights reserved.
4 *
5 * Developer: Wm. Daryl Hawkins
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 */
28
29/*
30 * Intel ICH Watchdog Timer (WDT) driver
31 *
32 * Originally developed by Wm. Daryl Hawkins of Texas A&M
33 * Heavily modified by <des@FreeBSD.org>
34 *
35 * This is a tricky one.  The ICH WDT can't be treated as a regular PCI
36 * device as it's actually an integrated function of the ICH LPC interface
37 * bridge.  Detection is also awkward, because we can only infer the
38 * presence of the watchdog timer from the fact that the machine has an
39 * ICH chipset, or, on ACPI 2.x systems, by the presence of the 'WDDT'
40 * ACPI table (although this driver does not support the ACPI detection
41 * method).
42 *
43 * There is one slight problem on non-ACPI or ACPI 1.x systems: we have no
44 * way of knowing if the WDT is permanently disabled (either by the BIOS
45 * or in hardware).
46 *
47 * The WDT is programmed through I/O registers in the ACPI I/O space.
48 * Intel swears it's always at offset 0x60, so we use that.
49 *
50 * For details about the ICH WDT, see Intel Application Note AP-725
51 * (document no. 292273-001).  The WDT is also described in the individual
52 * chipset datasheets, e.g. Intel82801EB ICH5 / 82801ER ICH5R Datasheet
53 * (document no. 252516-001) sections 9.10 and 9.11.
54 *
55 * ICH6/7/8 support by Takeharu KATO <takeharu1219@ybb.ne.jp>
56 */
57
58#include <sys/cdefs.h>
59__FBSDID("$FreeBSD: head/sys/dev/ichwd/ichwd.c 199015 2009-11-07 11:41:23Z avg $");
60
61#include <sys/param.h>
62#include <sys/kernel.h>
63#include <sys/module.h>
64#include <sys/systm.h>
65#include <sys/bus.h>
66#include <machine/bus.h>
67#include <sys/rman.h>
68#include <machine/resource.h>
69#include <sys/watchdog.h>
70
71#include <isa/isavar.h>
72#include <dev/pci/pcivar.h>
73
74#include <dev/ichwd/ichwd.h>
75
76static struct ichwd_device ichwd_devices[] = {
77	{ DEVICEID_82801AA,  "Intel 82801AA watchdog timer",	1 },
78	{ DEVICEID_82801AB,  "Intel 82801AB watchdog timer",	1 },
79	{ DEVICEID_82801BA,  "Intel 82801BA watchdog timer",	2 },
80	{ DEVICEID_82801BAM, "Intel 82801BAM watchdog timer",	2 },
81	{ DEVICEID_82801CA,  "Intel 82801CA watchdog timer",	3 },
82	{ DEVICEID_82801CAM, "Intel 82801CAM watchdog timer",	3 },
83	{ DEVICEID_82801DB,  "Intel 82801DB watchdog timer",	4 },
84	{ DEVICEID_82801DBM, "Intel 82801DBM watchdog timer",	4 },
85	{ DEVICEID_82801E,   "Intel 82801E watchdog timer",	5 },
86	{ DEVICEID_82801EB,  "Intel 82801EB watchdog timer",	5 },
87	{ DEVICEID_82801EBR, "Intel 82801EB/ER watchdog timer",	5 },
88	{ DEVICEID_6300ESB,  "Intel 6300ESB watchdog timer",	5 },
89	{ DEVICEID_82801FBR, "Intel 82801FB/FR watchdog timer",	6 },
90	{ DEVICEID_ICH6M,    "Intel ICH6M watchdog timer",	6 },
91	{ DEVICEID_ICH6W,    "Intel ICH6W watchdog timer",	6 },
92	{ DEVICEID_ICH7,     "Intel ICH7 watchdog timer",	7 },
93	{ DEVICEID_ICH7DH,   "Intel ICH7DH watchdog timer",	7 },
94	{ DEVICEID_ICH7M,    "Intel ICH7M watchdog timer",	7 },
95	{ DEVICEID_ICH7MDH,  "Intel ICH7MDH watchdog timer",	7 },
96	{ DEVICEID_ICH8,     "Intel ICH8 watchdog timer",	8 },
97	{ DEVICEID_ICH8DH,   "Intel ICH8DH watchdog timer",	8 },
98	{ DEVICEID_ICH8DO,   "Intel ICH8DO watchdog timer",	8 },
99	{ DEVICEID_ICH8M,    "Intel ICH8M watchdog timer",	8 },
100	{ DEVICEID_ICH8ME,   "Intel ICH8M-E watchdog timer",	8 },
101	{ DEVICEID_63XXESB,  "Intel 63XXESB watchdog timer",	8 },
102	{ DEVICEID_ICH9,     "Intel ICH9 watchdog timer",	9 },
103	{ DEVICEID_ICH9DH,   "Intel ICH9DH watchdog timer",	9 },
104	{ DEVICEID_ICH9DO,   "Intel ICH9DO watchdog timer",	9 },
105	{ DEVICEID_ICH9M,    "Intel ICH9M watchdog timer",	9 },
106	{ DEVICEID_ICH9ME,   "Intel ICH9M-E watchdog timer",	9 },
107	{ DEVICEID_ICH9R,    "Intel ICH9R watchdog timer",	9 },
108	{ DEVICEID_ICH10,    "Intel ICH10 watchdog timer",	10 },
109	{ DEVICEID_ICH10D,   "Intel ICH10D watchdog timer",	10 },
110	{ DEVICEID_ICH10DO,  "Intel ICH10DO watchdog timer",	10 },
111	{ DEVICEID_ICH10R,   "Intel ICH10R watchdog timer",	10 },
112	{ 0, NULL, 0 },
113};
114
115static devclass_t ichwd_devclass;
116
117#define ichwd_read_tco_1(sc, off) \
118	bus_space_read_1((sc)->tco_bst, (sc)->tco_bsh, (off))
119#define ichwd_read_tco_2(sc, off) \
120	bus_space_read_2((sc)->tco_bst, (sc)->tco_bsh, (off))
121#define ichwd_read_tco_4(sc, off) \
122	bus_space_read_4((sc)->tco_bst, (sc)->tco_bsh, (off))
123#define ichwd_read_smi_4(sc, off) \
124	bus_space_read_4((sc)->smi_bst, (sc)->smi_bsh, (off))
125#define ichwd_read_gcs_4(sc, off) \
126	bus_space_read_4((sc)->gcs_bst, (sc)->gcs_bsh, (off))
127
128#define ichwd_write_tco_1(sc, off, val) \
129	bus_space_write_1((sc)->tco_bst, (sc)->tco_bsh, (off), (val))
130#define ichwd_write_tco_2(sc, off, val) \
131	bus_space_write_2((sc)->tco_bst, (sc)->tco_bsh, (off), (val))
132#define ichwd_write_tco_4(sc, off, val) \
133	bus_space_write_4((sc)->tco_bst, (sc)->tco_bsh, (off), (val))
134#define ichwd_write_smi_4(sc, off, val) \
135	bus_space_write_4((sc)->smi_bst, (sc)->smi_bsh, (off), (val))
136#define ichwd_write_gcs_4(sc, off, val) \
137	bus_space_write_4((sc)->gcs_bst, (sc)->gcs_bsh, (off), (val))
138
139#define ichwd_verbose_printf(dev, ...) \
140	do {						\
141		if (bootverbose)			\
142			device_printf(dev, __VA_ARGS__);\
143	} while (0)
144
145/*
146 * Disable the watchdog timeout SMI handler.
147 *
148 * Apparently, some BIOSes install handlers that reset or disable the
149 * watchdog timer instead of resetting the system, so we disable the SMI
150 * (by clearing the SMI_TCO_EN bit of the SMI_EN register) to prevent this
151 * from happening.
152 */
153static __inline void
154ichwd_smi_disable(struct ichwd_softc *sc)
155{
156	ichwd_write_smi_4(sc, SMI_EN, ichwd_read_smi_4(sc, SMI_EN) & ~SMI_TCO_EN);
157}
158
159/*
160 * Enable the watchdog timeout SMI handler.  See above for details.
161 */
162static __inline void
163ichwd_smi_enable(struct ichwd_softc *sc)
164{
165	ichwd_write_smi_4(sc, SMI_EN, ichwd_read_smi_4(sc, SMI_EN) | SMI_TCO_EN);
166}
167
168/*
169 * Reset the watchdog status bits.
170 */
171static __inline void
172ichwd_sts_reset(struct ichwd_softc *sc)
173{
174	/*
175	 * The watchdog status bits are set to 1 by the hardware to
176	 * indicate various conditions.  They can be cleared by software
177	 * by writing a 1, not a 0.
178	 */
179	ichwd_write_tco_2(sc, TCO1_STS, TCO_TIMEOUT);
180	/*
181	 * XXX The datasheet says that TCO_SECOND_TO_STS must be cleared
182	 * before TCO_BOOT_STS, not the other way around.
183	 */
184	ichwd_write_tco_2(sc, TCO2_STS, TCO_BOOT_STS);
185	ichwd_write_tco_2(sc, TCO2_STS, TCO_SECOND_TO_STS);
186}
187
188/*
189 * Enable the watchdog timer by clearing the TCO_TMR_HALT bit in the
190 * TCO1_CNT register.  This is complicated by the need to preserve bit 9
191 * of that same register, and the requirement that all other bits must be
192 * written back as zero.
193 */
194static __inline void
195ichwd_tmr_enable(struct ichwd_softc *sc)
196{
197	uint16_t cnt;
198
199	cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE;
200	ichwd_write_tco_2(sc, TCO1_CNT, cnt & ~TCO_TMR_HALT);
201	sc->active = 1;
202	ichwd_verbose_printf(sc->device, "timer enabled\n");
203}
204
205/*
206 * Disable the watchdog timer.  See above for details.
207 */
208static __inline void
209ichwd_tmr_disable(struct ichwd_softc *sc)
210{
211	uint16_t cnt;
212
213	cnt = ichwd_read_tco_2(sc, TCO1_CNT) & TCO_CNT_PRESERVE;
214	ichwd_write_tco_2(sc, TCO1_CNT, cnt | TCO_TMR_HALT);
215	sc->active = 0;
216	ichwd_verbose_printf(sc->device, "timer disabled\n");
217}
218
219/*
220 * Reload the watchdog timer: writing anything to any of the lower five
221 * bits of the TCO_RLD register reloads the timer from the last value
222 * written to TCO_TMR.
223 */
224static __inline void
225ichwd_tmr_reload(struct ichwd_softc *sc)
226{
227	if (sc->ich_version <= 5)
228		ichwd_write_tco_1(sc, TCO_RLD, 1);
229	else
230		ichwd_write_tco_2(sc, TCO_RLD, 1);
231
232	ichwd_verbose_printf(sc->device, "timer reloaded\n");
233}
234
235/*
236 * Set the initial timeout value.  Note that this must always be followed
237 * by a reload.
238 */
239static __inline void
240ichwd_tmr_set(struct ichwd_softc *sc, unsigned int timeout)
241{
242
243	/*
244	 * If the datasheets are to be believed, the minimum value
245	 * actually varies from chipset to chipset - 4 for ICH5 and 2 for
246	 * all other chipsets.  I suspect this is a bug in the ICH5
247	 * datasheet and that the minimum is uniformly 2, but I'd rather
248	 * err on the side of caution.
249	 */
250	if (timeout < 4)
251		timeout = 4;
252
253	if (sc->ich_version <= 5) {
254		uint8_t tmr_val8 = ichwd_read_tco_1(sc, TCO_TMR1);
255
256		tmr_val8 &= 0xc0;
257		if (timeout > 0xbf)
258			timeout = 0xbf;
259		tmr_val8 |= timeout;
260		ichwd_write_tco_1(sc, TCO_TMR1, tmr_val8);
261	} else {
262		uint16_t tmr_val16 = ichwd_read_tco_2(sc, TCO_TMR2);
263
264		tmr_val16 &= 0xfc00;
265		if (timeout > 0x03ff)
266			timeout = 0x03ff;
267		tmr_val16 |= timeout;
268		ichwd_write_tco_2(sc, TCO_TMR2, tmr_val16);
269	}
270
271	sc->timeout = timeout;
272
273	ichwd_verbose_printf(sc->device, "timeout set to %u ticks\n", timeout);
274}
275
276static __inline int
277ichwd_clear_noreboot(struct ichwd_softc *sc)
278{
279	uint32_t status;
280	int rc = 0;
281
282	/* try to clear the NO_REBOOT bit */
283	if (sc->ich_version <= 5) {
284		status = pci_read_config(sc->ich, ICH_GEN_STA, 1);
285		status &= ~ICH_GEN_STA_NO_REBOOT;
286		pci_write_config(sc->ich, ICH_GEN_STA, status, 1);
287		status = pci_read_config(sc->ich, ICH_GEN_STA, 1);
288		if (status & ICH_GEN_STA_NO_REBOOT)
289			rc = EIO;
290	} else {
291		status = ichwd_read_gcs_4(sc, 0);
292		status &= ~ICH_GCS_NO_REBOOT;
293		ichwd_write_gcs_4(sc, 0, status);
294		status = ichwd_read_gcs_4(sc, 0);
295		if (status & ICH_GCS_NO_REBOOT)
296			rc = EIO;
297	}
298
299	if (rc)
300		device_printf(sc->device,
301		    "ICH WDT present but disabled in BIOS or hardware\n");
302
303	return (rc);
304}
305
306/*
307 * Watchdog event handler - called by the framework to enable or disable
308 * the watchdog or change the initial timeout value.
309 */
310static void
311ichwd_event(void *arg, unsigned int cmd, int *error)
312{
313	struct ichwd_softc *sc = arg;
314	unsigned int timeout;
315
316	/* convert from power-of-two-ns to WDT ticks */
317	cmd &= WD_INTERVAL;
318	timeout = ((uint64_t)1 << cmd) / ICHWD_TICK;
319	if (cmd) {
320		if (timeout != sc->timeout) {
321			if (!sc->active)
322				ichwd_tmr_enable(sc);
323			ichwd_tmr_set(sc, timeout);
324		}
325		ichwd_tmr_reload(sc);
326		*error = 0;
327	} else {
328		if (sc->active)
329			ichwd_tmr_disable(sc);
330	}
331}
332
333static device_t
334ichwd_find_ich_lpc_bridge(struct ichwd_device **id_p)
335{
336	struct ichwd_device *id;
337	device_t ich = NULL;
338
339	/* look for an ICH LPC interface bridge */
340	for (id = ichwd_devices; id->desc != NULL; ++id)
341		if ((ich = pci_find_device(VENDORID_INTEL, id->device)) != NULL)
342			break;
343
344	if (ich == NULL)
345		return (NULL);
346
347	ichwd_verbose_printf(ich, "found ICH%d or equivalent chipset: %s\n",
348	    id->version, id->desc);
349
350	if (id_p)
351		*id_p = id;
352
353	return (ich);
354}
355
356/*
357 * Look for an ICH LPC interface bridge.  If one is found, register an
358 * ichwd device.  There can be only one.
359 */
360static void
361ichwd_identify(driver_t *driver, device_t parent)
362{
363	struct ichwd_device *id_p;
364	device_t ich = NULL;
365	device_t dev;
366	uint32_t rcba;
367	int rc;
368
369	ich = ichwd_find_ich_lpc_bridge(&id_p);
370	if (ich == NULL)
371		return;
372
373	/* good, add child to bus */
374	if ((dev = device_find_child(parent, driver->name, 0)) == NULL)
375		dev = BUS_ADD_CHILD(parent, 0, driver->name, 0);
376
377	if (dev == NULL)
378		return;
379
380	device_set_desc_copy(dev, id_p->desc);
381
382	if (id_p->version >= 6) {
383		/* get RCBA (root complex base address) */
384		rcba = pci_read_config(ich, ICH_RCBA, 4);
385		rc = bus_set_resource(ich, SYS_RES_MEMORY, 0,
386		    (rcba & 0xffffc000) + ICH_GCS_OFFSET, ICH_GCS_SIZE);
387		if (rc)
388			ichwd_verbose_printf(dev,
389			    "Can not set memory resource for RCBA\n");
390	}
391}
392
393static int
394ichwd_probe(device_t dev)
395{
396
397	/* Do not claim some ISA PnP device by accident. */
398	if (isa_get_logicalid(dev) != 0)
399		return (ENXIO);
400	return (0);
401}
402
403static int
404ichwd_attach(device_t dev)
405{
406	struct ichwd_softc *sc;
407	struct ichwd_device *id_p;
408	device_t ich;
409	unsigned int pmbase = 0;
410
411	sc = device_get_softc(dev);
412	sc->device = dev;
413
414	ich = ichwd_find_ich_lpc_bridge(&id_p);
415	if (ich == NULL) {
416		device_printf(sc->device, "Can not find ICH device.\n");
417		goto fail;
418	}
419	sc->ich = ich;
420	sc->ich_version = id_p->version;
421
422	/* get ACPI base address */
423	pmbase = pci_read_config(ich, ICH_PMBASE, 2) & ICH_PMBASE_MASK;
424	if (pmbase == 0) {
425		device_printf(dev, "ICH PMBASE register is empty\n");
426		goto fail;
427	}
428
429	/* allocate I/O register space */
430	sc->smi_rid = 0;
431	sc->smi_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->smi_rid,
432	    pmbase + SMI_BASE, pmbase + SMI_BASE + SMI_LEN - 1, SMI_LEN,
433	    RF_ACTIVE | RF_SHAREABLE);
434	if (sc->smi_res == NULL) {
435		device_printf(dev, "unable to reserve SMI registers\n");
436		goto fail;
437	}
438	sc->smi_bst = rman_get_bustag(sc->smi_res);
439	sc->smi_bsh = rman_get_bushandle(sc->smi_res);
440
441	sc->tco_rid = 1;
442	sc->tco_res = bus_alloc_resource(dev, SYS_RES_IOPORT, &sc->tco_rid,
443	    pmbase + TCO_BASE, pmbase + TCO_BASE + TCO_LEN - 1, TCO_LEN,
444	    RF_ACTIVE | RF_SHAREABLE);
445	if (sc->tco_res == NULL) {
446		device_printf(dev, "unable to reserve TCO registers\n");
447		goto fail;
448	}
449	sc->tco_bst = rman_get_bustag(sc->tco_res);
450	sc->tco_bsh = rman_get_bushandle(sc->tco_res);
451
452	sc->gcs_rid = 0;
453	if (sc->ich_version >= 6) {
454		sc->gcs_res = bus_alloc_resource_any(ich, SYS_RES_MEMORY,
455		    &sc->gcs_rid, RF_ACTIVE|RF_SHAREABLE);
456		if (sc->gcs_res == NULL) {
457			device_printf(dev, "unable to reserve GCS registers\n");
458			goto fail;
459		}
460		sc->gcs_bst = rman_get_bustag(sc->gcs_res);
461		sc->gcs_bsh = rman_get_bushandle(sc->gcs_res);
462	} else {
463		sc->gcs_res = 0;
464		sc->gcs_bst = 0;
465		sc->gcs_bsh = 0;
466	}
467
468	if (ichwd_clear_noreboot(sc) != 0)
469		goto fail;
470
471	ichwd_verbose_printf(dev, "%s (ICH%d or equivalent)\n",
472	    device_get_desc(dev), sc->ich_version);
473
474	/*
475	 * XXX we should check the status registers (specifically, the
476	 * TCO_SECOND_TO_STS bit in the TCO2_STS register) to see if we
477	 * just came back from a watchdog-induced reset, and let the user
478	 * know.
479	 */
480
481	/* reset the watchdog status registers */
482	ichwd_sts_reset(sc);
483
484	/* make sure the WDT starts out inactive */
485	ichwd_tmr_disable(sc);
486
487	/* register the watchdog event handler */
488	sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, ichwd_event, sc, 0);
489
490	/* disable the SMI handler */
491	ichwd_smi_disable(sc);
492
493	return (0);
494 fail:
495	sc = device_get_softc(dev);
496	if (sc->tco_res != NULL)
497		bus_release_resource(dev, SYS_RES_IOPORT,
498		    sc->tco_rid, sc->tco_res);
499	if (sc->smi_res != NULL)
500		bus_release_resource(dev, SYS_RES_IOPORT,
501		    sc->smi_rid, sc->smi_res);
502	if (sc->gcs_res != NULL)
503		bus_release_resource(ich, SYS_RES_MEMORY,
504		    sc->gcs_rid, sc->gcs_res);
505
506	return (ENXIO);
507}
508
509static int
510ichwd_detach(device_t dev)
511{
512	struct ichwd_softc *sc;
513	device_t ich = NULL;
514
515	sc = device_get_softc(dev);
516
517	/* halt the watchdog timer */
518	if (sc->active)
519		ichwd_tmr_disable(sc);
520
521	/* enable the SMI handler */
522	ichwd_smi_enable(sc);
523
524	/* deregister event handler */
525	if (sc->ev_tag != NULL)
526		EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag);
527	sc->ev_tag = NULL;
528
529	/* reset the watchdog status registers */
530	ichwd_sts_reset(sc);
531
532	/* deallocate I/O register space */
533	bus_release_resource(dev, SYS_RES_IOPORT, sc->tco_rid, sc->tco_res);
534	bus_release_resource(dev, SYS_RES_IOPORT, sc->smi_rid, sc->smi_res);
535
536	/* deallocate memory resource */
537	ich = ichwd_find_ich_lpc_bridge(NULL);
538	if (sc->gcs_res && ich)
539		bus_release_resource(ich, SYS_RES_MEMORY, sc->gcs_rid, sc->gcs_res);
540
541	return (0);
542}
543
544static device_method_t ichwd_methods[] = {
545	DEVMETHOD(device_identify, ichwd_identify),
546	DEVMETHOD(device_probe,	ichwd_probe),
547	DEVMETHOD(device_attach, ichwd_attach),
548	DEVMETHOD(device_detach, ichwd_detach),
549	DEVMETHOD(device_shutdown, ichwd_detach),
550	{0,0}
551};
552
553static driver_t ichwd_driver = {
554	"ichwd",
555	ichwd_methods,
556	sizeof(struct ichwd_softc),
557};
558
559DRIVER_MODULE(ichwd, isa, ichwd_driver, ichwd_devclass, NULL, NULL);
560