root/dev/pci/ichwdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ichwdt_unlock_write
  2. ichwdt_match
  3. ichwdt_attach
  4. ichwdt_cb

    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 }

/* [<][>][^][v][top][bottom][index][help] */