The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/amdsbwd/amdsbwd.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2009 Andriy Gapon <avg@FreeBSD.org>
    5  * All rights reserved.
    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  * This is a driver for watchdog timer present in AMD SB600/SB7xx/SB8xx
   31  * southbridges.
   32  * Please see the following specifications for the descriptions of the
   33  * registers and flags:
   34  * - AMD SB600 Register Reference Guide, Public Version,  Rev. 3.03 (SB600 RRG)
   35  *   http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/46155_sb600_rrg_pub_3.03.pdf
   36  * - AMD SB700/710/750 Register Reference Guide (RRG)
   37  *   http://developer.amd.com/assets/43009_sb7xx_rrg_pub_1.00.pdf
   38  * - AMD SB700/710/750 Register Programming Requirements (RPR)
   39  *   http://developer.amd.com/assets/42413_sb7xx_rpr_pub_1.00.pdf
   40  * - AMD SB800-Series Southbridges Register Reference Guide (RRG)
   41  *   http://support.amd.com/us/Embedded_TechDocs/45482.pdf
   42  * Please see the following for Watchdog Resource Table specification:
   43  * - Watchdog Timer Hardware Requirements for Windows Server 2003 (WDRT)
   44  *   http://www.microsoft.com/whdc/system/sysinternals/watchdog.mspx
   45  * AMD SB600/SB7xx/SB8xx watchdog hardware seems to conform to the above
   46  * specifications, but the table hasn't been spotted in the wild yet.
   47  */
   48 
   49 #include <sys/cdefs.h>
   50 __FBSDID("$FreeBSD$");
   51 
   52 #include "opt_amdsbwd.h"
   53 
   54 #include <sys/param.h>
   55 #include <sys/kernel.h>
   56 #include <sys/module.h>
   57 #include <sys/systm.h>
   58 #include <sys/sysctl.h>
   59 #include <sys/bus.h>
   60 #include <machine/bus.h>
   61 #include <sys/rman.h>
   62 #include <machine/cputypes.h>
   63 #include <machine/md_var.h>
   64 #include <machine/resource.h>
   65 #include <sys/watchdog.h>
   66 
   67 #include <dev/pci/pcivar.h>
   68 #include <dev/amdsbwd/amd_chipset.h>
   69 #include <isa/isavar.h>
   70 
   71 /*
   72  * Registers in the Watchdog IO space.
   73  * See SB7xx RRG 2.3.4, WDRT.
   74  */
   75 #define AMDSB_WD_CTRL                   0x00
   76 #define         AMDSB_WD_RUN            0x01
   77 #define         AMDSB_WD_FIRED          0x02
   78 #define         AMDSB_WD_SHUTDOWN       0x04
   79 #define         AMDSB_WD_DISABLE        0x08
   80 #define         AMDSB_WD_RESERVED       0x70
   81 #define         AMDSB_WD_RELOAD         0x80
   82 #define AMDSB_WD_COUNT                  0x04
   83 #define         AMDSB_WD_COUNT_MASK     0xffff
   84 #define AMDSB_WDIO_REG_WIDTH            4
   85 
   86 #define amdsbwd_verbose_printf(dev, ...)        \
   87         do {                                            \
   88                 if (bootverbose)                        \
   89                         device_printf(dev, __VA_ARGS__);\
   90         } while (0)
   91 
   92 struct amdsbwd_softc {
   93         device_t                dev;
   94         eventhandler_tag        ev_tag;
   95         struct resource         *res_ctrl;
   96         struct resource         *res_count;
   97         int                     rid_ctrl;
   98         int                     rid_count;
   99         int                     ms_per_tick;
  100         int                     max_ticks;
  101         int                     active;
  102         unsigned int            timeout;
  103 };
  104 
  105 static void     amdsbwd_identify(driver_t *driver, device_t parent);
  106 static int      amdsbwd_probe(device_t dev);
  107 static int      amdsbwd_attach(device_t dev);
  108 static int      amdsbwd_detach(device_t dev);
  109 static int      amdsbwd_suspend(device_t dev);
  110 static int      amdsbwd_resume(device_t dev);
  111 
  112 static device_method_t amdsbwd_methods[] = {
  113         DEVMETHOD(device_identify,      amdsbwd_identify),
  114         DEVMETHOD(device_probe,         amdsbwd_probe),
  115         DEVMETHOD(device_attach,        amdsbwd_attach),
  116         DEVMETHOD(device_detach,        amdsbwd_detach),
  117         DEVMETHOD(device_suspend,       amdsbwd_suspend),
  118         DEVMETHOD(device_resume,        amdsbwd_resume),
  119 #if 0
  120         DEVMETHOD(device_shutdown,      amdsbwd_detach),
  121 #endif
  122         DEVMETHOD_END
  123 };
  124 
  125 static devclass_t       amdsbwd_devclass;
  126 static driver_t         amdsbwd_driver = {
  127         "amdsbwd",
  128         amdsbwd_methods,
  129         sizeof(struct amdsbwd_softc)
  130 };
  131 
  132 DRIVER_MODULE(amdsbwd, isa, amdsbwd_driver, amdsbwd_devclass, NULL, NULL);
  133 
  134 
  135 static uint8_t
  136 pmio_read(struct resource *res, uint8_t reg)
  137 {
  138         bus_write_1(res, 0, reg);       /* Index */
  139         return (bus_read_1(res, 1));    /* Data */
  140 }
  141 
  142 static void
  143 pmio_write(struct resource *res, uint8_t reg, uint8_t val)
  144 {
  145         bus_write_1(res, 0, reg);       /* Index */
  146         bus_write_1(res, 1, val);       /* Data */
  147 }
  148 
  149 static uint32_t
  150 wdctrl_read(struct amdsbwd_softc *sc)
  151 {
  152         return (bus_read_4(sc->res_ctrl, 0));
  153 }
  154 
  155 static void
  156 wdctrl_write(struct amdsbwd_softc *sc, uint32_t val)
  157 {
  158         bus_write_4(sc->res_ctrl, 0, val);
  159 }
  160 
  161 static __unused uint32_t
  162 wdcount_read(struct amdsbwd_softc *sc)
  163 {
  164         return (bus_read_4(sc->res_count, 0));
  165 }
  166 
  167 static void
  168 wdcount_write(struct amdsbwd_softc *sc, uint32_t val)
  169 {
  170         bus_write_4(sc->res_count, 0, val);
  171 }
  172 
  173 static void
  174 amdsbwd_tmr_enable(struct amdsbwd_softc *sc)
  175 {
  176         uint32_t val;
  177 
  178         val = wdctrl_read(sc);
  179         val |= AMDSB_WD_RUN;
  180         wdctrl_write(sc, val);
  181         sc->active = 1;
  182         amdsbwd_verbose_printf(sc->dev, "timer enabled\n");
  183 }
  184 
  185 static void
  186 amdsbwd_tmr_disable(struct amdsbwd_softc *sc)
  187 {
  188         uint32_t val;
  189 
  190         val = wdctrl_read(sc);
  191         val &= ~AMDSB_WD_RUN;
  192         wdctrl_write(sc, val);
  193         sc->active = 0;
  194         amdsbwd_verbose_printf(sc->dev, "timer disabled\n");
  195 }
  196 
  197 static void
  198 amdsbwd_tmr_reload(struct amdsbwd_softc *sc)
  199 {
  200         uint32_t val;
  201 
  202         val = wdctrl_read(sc);
  203         val |= AMDSB_WD_RELOAD;
  204         wdctrl_write(sc, val);
  205 }
  206 
  207 static void
  208 amdsbwd_tmr_set(struct amdsbwd_softc *sc, uint16_t timeout)
  209 {
  210 
  211         timeout &= AMDSB_WD_COUNT_MASK;
  212         wdcount_write(sc, timeout);
  213         sc->timeout = timeout;
  214         amdsbwd_verbose_printf(sc->dev, "timeout set to %u ticks\n", timeout);
  215 }
  216 
  217 static void
  218 amdsbwd_event(void *arg, unsigned int cmd, int *error)
  219 {
  220         struct amdsbwd_softc *sc = arg;
  221         uint64_t timeout;
  222 
  223         if (cmd != 0) {
  224                 timeout = 0;
  225                 cmd &= WD_INTERVAL;
  226                 if (cmd >= WD_TO_1MS) {
  227                         timeout = (uint64_t)1 << (cmd - WD_TO_1MS);
  228                         timeout = timeout / sc->ms_per_tick;
  229                 }
  230                 /* For a too short timeout use 1 tick. */
  231                 if (timeout == 0)
  232                         timeout = 1;
  233                 /* For a too long timeout stop the timer. */
  234                 if (timeout > sc->max_ticks)
  235                         timeout = 0;
  236         } else {
  237                 timeout = 0;
  238         }
  239 
  240         if (timeout != 0) {
  241                 if (timeout != sc->timeout)
  242                         amdsbwd_tmr_set(sc, timeout);
  243                 if (!sc->active)
  244                         amdsbwd_tmr_enable(sc);
  245                 amdsbwd_tmr_reload(sc);
  246                 *error = 0;
  247         } else {
  248                 if (sc->active)
  249                         amdsbwd_tmr_disable(sc);
  250         }
  251 }
  252 
  253 static void
  254 amdsbwd_identify(driver_t *driver, device_t parent)
  255 {
  256         device_t                child;
  257         device_t                smb_dev;
  258 
  259         if (resource_disabled("amdsbwd", 0))
  260                 return;
  261         if (device_find_child(parent, "amdsbwd", -1) != NULL)
  262                 return;
  263 
  264         /*
  265          * Try to identify SB600/SB7xx by PCI Device ID of SMBus device
  266          * that should be present at bus 0, device 20, function 0.
  267          */
  268         smb_dev = pci_find_bsf(0, 20, 0);
  269         if (smb_dev == NULL)
  270                 return;
  271         if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID &&
  272             pci_get_devid(smb_dev) != AMDFCH_SMBUS_DEVID &&
  273             pci_get_devid(smb_dev) != AMDCZ_SMBUS_DEVID &&
  274             pci_get_devid(smb_dev) != HYGONCZ_SMBUS_DEVID)
  275                 return;
  276 
  277         child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "amdsbwd", -1);
  278         if (child == NULL)
  279                 device_printf(parent, "add amdsbwd child failed\n");
  280 }
  281 
  282 
  283 static void
  284 amdsbwd_probe_sb7xx(device_t dev, struct resource *pmres, uint32_t *addr)
  285 {
  286         uint8_t val;
  287         int     i;
  288 
  289         /* Report cause of previous reset for user's convenience. */
  290         val = pmio_read(pmres, AMDSB_PM_RESET_STATUS0);
  291         if (val != 0)
  292                 amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val);
  293         val = pmio_read(pmres, AMDSB_PM_RESET_STATUS1);
  294         if (val != 0)
  295                 amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val);
  296         if ((val & AMDSB_WD_RST_STS) != 0)
  297                 device_printf(dev, "Previous Reset was caused by Watchdog\n");
  298 
  299         /* Find base address of memory mapped WDT registers. */
  300         for (*addr = 0, i = 0; i < 4; i++) {
  301                 *addr <<= 8;
  302                 *addr |= pmio_read(pmres, AMDSB_PM_WDT_BASE_MSB - i);
  303         }
  304         *addr &= ~0x07u;
  305 
  306         /* Set watchdog timer tick to 1s. */
  307         val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
  308         val &= ~AMDSB_WDT_RES_MASK;
  309         val |= AMDSB_WDT_RES_1S;
  310         pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
  311 
  312         /* Enable watchdog device (in stopped state). */
  313         val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
  314         val &= ~AMDSB_WDT_DISABLE;
  315         pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
  316 
  317         /*
  318          * XXX TODO: Ensure that watchdog decode is enabled
  319          * (register 0x41, bit 3).
  320          */
  321         device_set_desc(dev, "AMD SB600/SB7xx Watchdog Timer");
  322 }
  323 
  324 static void
  325 amdsbwd_probe_sb8xx(device_t dev, struct resource *pmres, uint32_t *addr)
  326 {
  327         uint32_t        val;
  328         int             i;
  329 
  330         /* Report cause of previous reset for user's convenience. */
  331 
  332         val = pmio_read(pmres, AMDSB8_PM_RESET_CTRL);
  333         if ((val & AMDSB8_RST_STS_DIS) != 0) {
  334                 val &= ~AMDSB8_RST_STS_DIS;
  335                 pmio_write(pmres, AMDSB8_PM_RESET_CTRL, val);
  336         }
  337         val = 0;
  338         for (i = 3; i >= 0; i--) {
  339                 val <<= 8;
  340                 val |= pmio_read(pmres, AMDSB8_PM_RESET_STATUS + i);
  341         }
  342         if (val != 0)
  343                 amdsbwd_verbose_printf(dev, "ResetStatus = 0x%08x\n", val);
  344         if ((val & AMDSB8_WD_RST_STS) != 0)
  345                 device_printf(dev, "Previous Reset was caused by Watchdog\n");
  346 
  347         /* Find base address of memory mapped WDT registers. */
  348         for (*addr = 0, i = 0; i < 4; i++) {
  349                 *addr <<= 8;
  350                 *addr |= pmio_read(pmres, AMDSB8_PM_WDT_EN + 3 - i);
  351         }
  352         *addr &= ~0x07u;
  353 
  354         /* Set watchdog timer tick to 1s. */
  355         val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
  356         val &= ~AMDSB8_WDT_RES_MASK;
  357         val |= AMDSB8_WDT_1HZ;
  358         pmio_write(pmres, AMDSB8_PM_WDT_CTRL, val);
  359 #ifdef AMDSBWD_DEBUG
  360         val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
  361         amdsbwd_verbose_printf(dev, "AMDSB8_PM_WDT_CTRL value = %#04x\n", val);
  362 #endif
  363 
  364         /*
  365          * Enable watchdog device (in stopped state)
  366          * and decoding of its address.
  367          */
  368         val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
  369         val &= ~AMDSB8_WDT_DISABLE;
  370         val |= AMDSB8_WDT_DEC_EN;
  371         pmio_write(pmres, AMDSB8_PM_WDT_EN, val);
  372 #ifdef AMDSBWD_DEBUG
  373         val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
  374         device_printf(dev, "AMDSB8_PM_WDT_EN value = %#04x\n", val);
  375 #endif
  376         device_set_desc(dev, "AMD SB8xx/SB9xx/Axx Watchdog Timer");
  377 }
  378 
  379 static void
  380 amdsbwd_probe_fch41(device_t dev, struct resource *pmres, uint32_t *addr)
  381 {
  382         uint8_t val;
  383         char buf[36];
  384 
  385         /*
  386          * Enable decoding of watchdog MMIO address.
  387          */
  388         val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0);
  389         val |= AMDFCH41_WDT_EN;
  390         pmio_write(pmres, AMDFCH41_PM_DECODE_EN0, val);
  391 #ifdef AMDSBWD_DEBUG
  392         val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN0);
  393         device_printf(dev, "AMDFCH41_PM_DECODE_EN0 value = %#04x\n", val);
  394 #endif
  395 
  396         val = pmio_read(pmres, AMDFCH41_PM_ISA_CTRL);
  397         if ((val & AMDFCH41_MMIO_EN) != 0) {
  398                 /* Fixed offset for the watchdog within ACPI MMIO range. */
  399                 amdsbwd_verbose_printf(dev, "ACPI MMIO range is enabled\n");
  400                 *addr = AMDFCH41_MMIO_ADDR + AMDFCH41_MMIO_WDT_OFF;
  401         } else {
  402                 /* Special fixed MMIO range for the watchdog. */
  403                 *addr = AMDFCH41_WDT_FIXED_ADDR;
  404         }
  405 
  406         /*
  407          * Set watchdog timer tick to 1s and
  408          * enable the watchdog device (in stopped state).
  409          */
  410         val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3);
  411         val &= ~AMDFCH41_WDT_RES_MASK;
  412         val |= AMDFCH41_WDT_RES_1S;
  413         val &= ~AMDFCH41_WDT_EN_MASK;
  414         val |= AMDFCH41_WDT_ENABLE;
  415         pmio_write(pmres, AMDFCH41_PM_DECODE_EN3, val);
  416 #ifdef AMDSBWD_DEBUG
  417         val = pmio_read(pmres, AMDFCH41_PM_DECODE_EN3);
  418         amdsbwd_verbose_printf(dev, "AMDFCH41_PM_DECODE_EN3 value = %#04x\n",
  419             val);
  420 #endif
  421         snprintf(buf, sizeof(buf), "%s FCH Rev 41h+ Watchdog Timer",
  422             cpu_vendor_id == CPU_VENDOR_HYGON ? "Hygon" : "AMD");
  423         device_set_desc_copy(dev, buf);
  424 }
  425 
  426 static int
  427 amdsbwd_probe(device_t dev)
  428 {
  429         struct resource         *res;
  430         device_t                smb_dev;
  431         uint32_t                addr;
  432         int                     rid;
  433         int                     rc;
  434         uint32_t                devid;
  435         uint8_t                 revid;
  436 
  437         /* Do not claim some ISA PnP device by accident. */
  438         if (isa_get_logicalid(dev) != 0)
  439                 return (ENXIO);
  440 
  441         rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, AMDSB_PMIO_INDEX,
  442             AMDSB_PMIO_WIDTH);
  443         if (rc != 0) {
  444                 device_printf(dev, "bus_set_resource for IO failed\n");
  445                 return (ENXIO);
  446         }
  447         rid = 0;
  448         res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
  449             RF_ACTIVE | RF_SHAREABLE);
  450         if (res == NULL) {
  451                 device_printf(dev, "bus_alloc_resource for IO failed\n");
  452                 return (ENXIO);
  453         }
  454 
  455         smb_dev = pci_find_bsf(0, 20, 0);
  456         KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
  457         devid = pci_get_devid(smb_dev);
  458         revid = pci_get_revid(smb_dev);
  459         if (devid == AMDSB_SMBUS_DEVID && revid < AMDSB8_SMBUS_REVID)
  460                 amdsbwd_probe_sb7xx(dev, res, &addr);
  461         else if (devid == AMDSB_SMBUS_DEVID ||
  462             (devid == AMDFCH_SMBUS_DEVID && revid < AMDFCH41_SMBUS_REVID) ||
  463             (devid == AMDCZ_SMBUS_DEVID  && revid < AMDCZ49_SMBUS_REVID))
  464                 amdsbwd_probe_sb8xx(dev, res, &addr);
  465         else
  466                 amdsbwd_probe_fch41(dev, res, &addr);
  467 
  468         bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
  469         bus_delete_resource(dev, SYS_RES_IOPORT, rid);
  470 
  471         amdsbwd_verbose_printf(dev, "memory base address = %#010x\n", addr);
  472         rc = bus_set_resource(dev, SYS_RES_MEMORY, 0, addr + AMDSB_WD_CTRL,
  473             AMDSB_WDIO_REG_WIDTH);
  474         if (rc != 0) {
  475                 device_printf(dev, "bus_set_resource for control failed\n");
  476                 return (ENXIO);
  477         }
  478         rc = bus_set_resource(dev, SYS_RES_MEMORY, 1, addr + AMDSB_WD_COUNT,
  479             AMDSB_WDIO_REG_WIDTH);
  480         if (rc != 0) {
  481                 device_printf(dev, "bus_set_resource for count failed\n");
  482                 return (ENXIO);
  483         }
  484 
  485         return (0);
  486 }
  487 
  488 static int
  489 amdsbwd_attach_sb(device_t dev, struct amdsbwd_softc *sc)
  490 {
  491 
  492         sc->max_ticks = UINT16_MAX;
  493         sc->rid_ctrl = 0;
  494         sc->rid_count = 1;
  495 
  496         sc->ms_per_tick = 1000;
  497 
  498         sc->res_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  499             &sc->rid_ctrl, RF_ACTIVE);
  500         if (sc->res_ctrl == NULL) {
  501                 device_printf(dev, "bus_alloc_resource for ctrl failed\n");
  502                 return (ENXIO);
  503         }
  504         sc->res_count = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  505             &sc->rid_count, RF_ACTIVE);
  506         if (sc->res_count == NULL) {
  507                 device_printf(dev, "bus_alloc_resource for count failed\n");
  508                 return (ENXIO);
  509         }
  510         return (0);
  511 }
  512 
  513 static int
  514 amdsbwd_attach(device_t dev)
  515 {
  516         struct amdsbwd_softc    *sc;
  517         int                     rc;
  518 
  519         sc = device_get_softc(dev);
  520         sc->dev = dev;
  521 
  522         rc = amdsbwd_attach_sb(dev, sc);
  523         if (rc != 0)
  524                 goto fail;
  525 
  526 #ifdef AMDSBWD_DEBUG
  527         device_printf(dev, "wd ctrl = %#04x\n", wdctrl_read(sc));
  528         device_printf(dev, "wd count = %#04x\n", wdcount_read(sc));
  529 #endif
  530 
  531         /* Setup initial state of Watchdog Control. */
  532         wdctrl_write(sc, AMDSB_WD_FIRED);
  533 
  534         if (wdctrl_read(sc) & AMDSB_WD_DISABLE) {
  535                 device_printf(dev, "watchdog hardware is disabled\n");
  536                 goto fail;
  537         }
  538 
  539         sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, amdsbwd_event, sc,
  540             EVENTHANDLER_PRI_ANY);
  541 
  542         return (0);
  543 
  544 fail:
  545         amdsbwd_detach(dev);
  546         return (ENXIO);
  547 }
  548 
  549 static int
  550 amdsbwd_detach(device_t dev)
  551 {
  552         struct amdsbwd_softc *sc;
  553 
  554         sc = device_get_softc(dev);
  555         if (sc->ev_tag != NULL)
  556                 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag);
  557 
  558         if (sc->active)
  559                 amdsbwd_tmr_disable(sc);
  560 
  561         if (sc->res_ctrl != NULL)
  562                 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ctrl,
  563                     sc->res_ctrl);
  564 
  565         if (sc->res_count != NULL)
  566                 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_count,
  567                     sc->res_count);
  568 
  569         return (0);
  570 }
  571 
  572 static int
  573 amdsbwd_suspend(device_t dev)
  574 {
  575         struct amdsbwd_softc *sc;
  576         uint32_t val;
  577 
  578         sc = device_get_softc(dev);
  579         val = wdctrl_read(sc);
  580         val &= ~AMDSB_WD_RUN;
  581         wdctrl_write(sc, val);
  582         return (0);
  583 }
  584 
  585 static int
  586 amdsbwd_resume(device_t dev)
  587 {
  588         struct amdsbwd_softc *sc;
  589 
  590         sc = device_get_softc(dev);
  591         wdctrl_write(sc, AMDSB_WD_FIRED);
  592         if (sc->active) {
  593                 amdsbwd_tmr_set(sc, sc->timeout);
  594                 amdsbwd_tmr_enable(sc);
  595                 amdsbwd_tmr_reload(sc);
  596         }
  597         return (0);
  598 }

Cache object: 328ec5309601dc30d32c5514e1f2a1ad


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.