[BACK]Return to ichwdt.c CVS log [TXT][DIR] Up to [local] / sys / dev / pci

Annotation of sys/dev/pci/ichwdt.c, Revision 1.1.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