Annotation of sys/dev/pci/ichwdt.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: ichwdt.c,v 1.2 2005/12/17 21:05:50 grange Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2004, 2005 Alexander Yurchenko <grange@openbsd.org>
! 5: *
! 6: * Permission to use, copy, modify, and distribute this software for any
! 7: * purpose with or without fee is hereby granted, provided that the above
! 8: * copyright notice and this permission notice appear in all copies.
! 9: *
! 10: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 11: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 12: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 13: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 14: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 15: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 16: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 17: */
! 18:
! 19: /*
! 20: * Intel 6300ESB ICH watchdog timer driver.
! 21: */
! 22:
! 23: #include <sys/param.h>
! 24: #include <sys/systm.h>
! 25: #include <sys/device.h>
! 26:
! 27: #include <machine/bus.h>
! 28:
! 29: #include <dev/pci/pcireg.h>
! 30: #include <dev/pci/pcivar.h>
! 31: #include <dev/pci/pcidevs.h>
! 32:
! 33: #include <dev/pci/ichreg.h>
! 34:
! 35: #ifdef ICHWDT_DEBUG
! 36: #define DPRINTF(x) printf x
! 37: #else
! 38: #define DPRINTF(x)
! 39: #endif
! 40:
! 41: struct ichwdt_softc {
! 42: struct device sc_dev;
! 43:
! 44: pci_chipset_tag_t sc_pc;
! 45: pcitag_t sc_tag;
! 46:
! 47: bus_space_tag_t sc_iot;
! 48: bus_space_handle_t sc_ioh;
! 49:
! 50: int sc_divisor;
! 51: int sc_period;
! 52: };
! 53:
! 54: int ichwdt_match(struct device *, void *, void *);
! 55: void ichwdt_attach(struct device *, struct device *, void *);
! 56:
! 57: int ichwdt_cb(void *, int);
! 58:
! 59: struct cfattach ichwdt_ca = {
! 60: sizeof(struct ichwdt_softc),
! 61: ichwdt_match,
! 62: ichwdt_attach
! 63: };
! 64:
! 65: struct cfdriver ichwdt_cd = {
! 66: NULL, "ichwdt", DV_DULL
! 67: };
! 68:
! 69: const struct pci_matchid ichwdt_devices[] = {
! 70: { PCI_VENDOR_INTEL, PCI_PRODUCT_INTEL_6300ESB_WDT }
! 71: };
! 72:
! 73: static __inline void
! 74: ichwdt_unlock_write(struct ichwdt_softc *sc, int reg, u_int32_t val)
! 75: {
! 76: /* Register unlocking sequence */
! 77: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ICH_WDT_RELOAD, 0x80);
! 78: bus_space_write_4(sc->sc_iot, sc->sc_ioh, ICH_WDT_RELOAD, 0x86);
! 79:
! 80: /* Now it's possible to write to the register */
! 81: bus_space_write_4(sc->sc_iot, sc->sc_ioh, reg, val);
! 82: }
! 83:
! 84: int
! 85: ichwdt_match(struct device *parent, void *match, void *aux)
! 86: {
! 87: return (pci_matchbyid((struct pci_attach_args *)aux, ichwdt_devices,
! 88: sizeof(ichwdt_devices) / sizeof(ichwdt_devices[0])));
! 89: }
! 90:
! 91: void
! 92: ichwdt_attach(struct device *parent, struct device *self, void *aux)
! 93: {
! 94: struct ichwdt_softc *sc = (struct ichwdt_softc *)self;
! 95: struct pci_attach_args *pa = aux;
! 96: u_int32_t reg;
! 97:
! 98: sc->sc_pc = pa->pa_pc;
! 99: sc->sc_tag = pa->pa_tag;
! 100:
! 101: /* Map memory space */
! 102: sc->sc_iot = pa->pa_iot;
! 103: if (pci_mapreg_map(pa, ICH_WDT_BASE, PCI_MAPREG_TYPE_MEM, 0,
! 104: &sc->sc_iot, &sc->sc_ioh, NULL, NULL, 0)) {
! 105: printf(": failed to map memory space\n");
! 106: return;
! 107: }
! 108:
! 109: /* Read current configuration */
! 110: reg = pci_conf_read(sc->sc_pc, sc->sc_tag, ICH_WDT_CONF);
! 111: DPRINTF((": conf 0x%x", reg));
! 112:
! 113: /* Get clock divisor */
! 114: sc->sc_divisor = (reg & ICH_WDT_CONF_PRE ? 32 : 32768);
! 115: printf(": %s clock", (reg & ICH_WDT_CONF_PRE ? "1MHz" : "1kHz"));
! 116:
! 117: /* Disable interrupts since we don't use first stage timeout alarm */
! 118: reg &= ~ICH_WDT_CONF_INT_MASK;
! 119: reg |= ICH_WDT_CONF_INT_DIS;
! 120: pci_conf_write(sc->sc_pc, sc->sc_tag, ICH_WDT_CONF, reg);
! 121:
! 122: /* Check for reboot on timeout */
! 123: reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, ICH_WDT_RELOAD);
! 124: if (reg & ICH_WDT_RELOAD_TIMEOUT) {
! 125: printf(": reboot on timeout");
! 126:
! 127: /* Clear timeout bit */
! 128: ichwdt_unlock_write(sc, ICH_WDT_RELOAD,
! 129: ICH_WDT_RELOAD_TIMEOUT);
! 130: }
! 131:
! 132: /* Disable watchdog */
! 133: pci_conf_write(sc->sc_pc, sc->sc_tag, ICH_WDT_LOCK, 0);
! 134: sc->sc_period = 0;
! 135:
! 136: printf("\n");
! 137:
! 138: /* Register new watchdog */
! 139: wdog_register(sc, ichwdt_cb);
! 140: }
! 141:
! 142: int
! 143: ichwdt_cb(void *arg, int period)
! 144: {
! 145: struct ichwdt_softc *sc = arg;
! 146: int ticks;
! 147:
! 148: if (period == 0) {
! 149: if (sc->sc_period != 0) {
! 150: /* Disable watchdog */
! 151: ichwdt_unlock_write(sc, ICH_WDT_RELOAD,
! 152: ICH_WDT_RELOAD_RLD);
! 153: pci_conf_write(sc->sc_pc, sc->sc_tag, ICH_WDT_LOCK, 0);
! 154: DPRINTF(("%s: disabled, conf 0x%x\n",
! 155: sc->sc_dev.dv_xname,
! 156: pci_conf_read(sc->sc_pc, sc->sc_tag,
! 157: ICH_WDT_LOCK)));
! 158: }
! 159: } else {
! 160: /* 1000s should be enough for everyone */
! 161: if (period > 1000)
! 162: period = 1000;
! 163:
! 164: if (sc->sc_period != period) {
! 165: /* Set new timeout */
! 166: ticks = (period * 33000000) / sc->sc_divisor;
! 167: ichwdt_unlock_write(sc, ICH_WDT_PRE1, ticks);
! 168: ichwdt_unlock_write(sc, ICH_WDT_PRE2, 2);
! 169: DPRINTF(("%s: timeout %ds (%d ticks)\n",
! 170: sc->sc_dev.dv_xname, period, ticks));
! 171: }
! 172: if (sc->sc_period == 0) {
! 173: /* Enable watchdog */
! 174: pci_conf_write(sc->sc_pc, sc->sc_tag, ICH_WDT_LOCK,
! 175: ICH_WDT_LOCK_ENABLED);
! 176: DPRINTF(("%s: enabled, conf 0x%x\n",
! 177: sc->sc_dev.dv_xname,
! 178: pci_conf_read(sc->sc_pc, sc->sc_tag,
! 179: ICH_WDT_LOCK)));
! 180: } else {
! 181: /* Reset timer */
! 182: ichwdt_unlock_write(sc, ICH_WDT_RELOAD,
! 183: ICH_WDT_RELOAD_RLD);
! 184: DPRINTF(("%s: reloaded\n", sc->sc_dev.dv_xname));
! 185: }
! 186: }
! 187: sc->sc_period = period;
! 188:
! 189: return (period);
! 190: }
CVSweb