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  * Copyright (c) 2009 Andriy Gapon <avg@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * This is a driver for watchdog timer present in AMD SB600/SB7xx/SB8xx
   29  * southbridges.
   30  * Please see the following specifications for the descriptions of the
   31  * registers and flags:
   32  * - AMD SB600 Register Reference Guide, Public Version,  Rev. 3.03 (SB600 RRG)
   33  *   http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/46155_sb600_rrg_pub_3.03.pdf
   34  * - AMD SB700/710/750 Register Reference Guide (RRG)
   35  *   http://developer.amd.com/assets/43009_sb7xx_rrg_pub_1.00.pdf
   36  * - AMD SB700/710/750 Register Programming Requirements (RPR)
   37  *   http://developer.amd.com/assets/42413_sb7xx_rpr_pub_1.00.pdf
   38  * - AMD SB800-Series Southbridges Register Reference Guide (RRG)
   39  *   http://support.amd.com/us/Embedded_TechDocs/45482.pdf
   40  * Please see the following for Watchdog Resource Table specification:
   41  * - Watchdog Timer Hardware Requirements for Windows Server 2003 (WDRT)
   42  *   http://www.microsoft.com/whdc/system/sysinternals/watchdog.mspx
   43  * AMD SB600/SB7xx/SB8xx watchdog hardware seems to conform to the above
   44  * specifications, but the table hasn't been spotted in the wild yet.
   45  */
   46 
   47 #include <sys/cdefs.h>
   48 __FBSDID("$FreeBSD: releng/11.0/sys/dev/amdsbwd/amdsbwd.c 297386 2016-03-29 12:19:46Z mav $");
   49 
   50 #include <sys/param.h>
   51 #include <sys/kernel.h>
   52 #include <sys/module.h>
   53 #include <sys/systm.h>
   54 #include <sys/sysctl.h>
   55 #include <sys/bus.h>
   56 #include <machine/bus.h>
   57 #include <sys/rman.h>
   58 #include <machine/resource.h>
   59 #include <sys/watchdog.h>
   60 
   61 #include <dev/pci/pcivar.h>
   62 #include <isa/isavar.h>
   63 
   64 /* SB7xx RRG 2.3.3.1.1. */
   65 #define AMDSB_PMIO_INDEX                0xcd6
   66 #define AMDSB_PMIO_DATA                 (PMIO_INDEX + 1)
   67 #define AMDSB_PMIO_WIDTH                2
   68 /* SB7xx RRG 2.3.3.2. */
   69 #define AMDSB_PM_RESET_STATUS0          0x44
   70 #define AMDSB_PM_RESET_STATUS1          0x45
   71 #define         AMDSB_WD_RST_STS        0x02
   72 /* SB7xx RRG 2.3.3.2, RPR 2.36. */
   73 #define AMDSB_PM_WDT_CTRL               0x69
   74 #define         AMDSB_WDT_DISABLE       0x01
   75 #define         AMDSB_WDT_RES_MASK      (0x02 | 0x04)
   76 #define         AMDSB_WDT_RES_32US      0x00
   77 #define         AMDSB_WDT_RES_10MS      0x02
   78 #define         AMDSB_WDT_RES_100MS     0x04
   79 #define         AMDSB_WDT_RES_1S        0x06
   80 #define AMDSB_PM_WDT_BASE_LSB           0x6c
   81 #define AMDSB_PM_WDT_BASE_MSB           0x6f
   82 /* SB8xx RRG 2.3.3. */
   83 #define AMDSB8_PM_WDT_EN                0x48
   84 #define         AMDSB8_WDT_DEC_EN       0x01
   85 #define         AMDSB8_WDT_DISABLE      0x02
   86 #define AMDSB8_PM_WDT_CTRL              0x4c
   87 #define         AMDSB8_WDT_32KHZ        0x00
   88 #define         AMDSB8_WDT_1HZ          0x03
   89 #define         AMDSB8_WDT_RES_MASK     0x03
   90 #define AMDSB8_PM_RESET_STATUS0         0xC0
   91 #define AMDSB8_PM_RESET_STATUS1         0xC1
   92 #define         AMDSB8_WD_RST_STS       0x20
   93 /* SB7xx RRG 2.3.4, WDRT. */
   94 #define AMDSB_WD_CTRL                   0x00
   95 #define         AMDSB_WD_RUN            0x01
   96 #define         AMDSB_WD_FIRED          0x02
   97 #define         AMDSB_WD_SHUTDOWN       0x04
   98 #define         AMDSB_WD_DISABLE        0x08
   99 #define         AMDSB_WD_RESERVED       0x70
  100 #define         AMDSB_WD_RELOAD         0x80
  101 #define AMDSB_WD_COUNT                  0x04
  102 #define         AMDSB_WD_COUNT_MASK     0xffff
  103 #define AMDSB_WDIO_REG_WIDTH            4
  104 /* WDRT */
  105 #define MAXCOUNT_MIN_VALUE              511
  106 /* SB7xx RRG 2.3.1.1, SB600 RRG 2.3.1.1, SB8xx RRG 2.3.1.  */
  107 #define AMDSB_SMBUS_DEVID               0x43851002
  108 #define AMDSB8_SMBUS_REVID              0x40
  109 #define AMDHUDSON_SMBUS_DEVID           0x780b1022
  110 #define AMDKERNCZ_SMBUS_DEVID           0x790b1022
  111 
  112 #define amdsbwd_verbose_printf(dev, ...)        \
  113         do {                                            \
  114                 if (bootverbose)                        \
  115                         device_printf(dev, __VA_ARGS__);\
  116         } while (0)
  117 
  118 struct amdsbwd_softc {
  119         device_t                dev;
  120         eventhandler_tag        ev_tag;
  121         struct resource         *res_ctrl;
  122         struct resource         *res_count;
  123         int                     rid_ctrl;
  124         int                     rid_count;
  125         int                     ms_per_tick;
  126         int                     max_ticks;
  127         int                     active;
  128         unsigned int            timeout;
  129 };
  130 
  131 static void     amdsbwd_identify(driver_t *driver, device_t parent);
  132 static int      amdsbwd_probe(device_t dev);
  133 static int      amdsbwd_attach(device_t dev);
  134 static int      amdsbwd_detach(device_t dev);
  135 
  136 static device_method_t amdsbwd_methods[] = {
  137         DEVMETHOD(device_identify,      amdsbwd_identify),
  138         DEVMETHOD(device_probe,         amdsbwd_probe),
  139         DEVMETHOD(device_attach,        amdsbwd_attach),
  140         DEVMETHOD(device_detach,        amdsbwd_detach),
  141 #if 0
  142         DEVMETHOD(device_shutdown,      amdsbwd_detach),
  143 #endif
  144         DEVMETHOD_END
  145 };
  146 
  147 static devclass_t       amdsbwd_devclass;
  148 static driver_t         amdsbwd_driver = {
  149         "amdsbwd",
  150         amdsbwd_methods,
  151         sizeof(struct amdsbwd_softc)
  152 };
  153 
  154 DRIVER_MODULE(amdsbwd, isa, amdsbwd_driver, amdsbwd_devclass, NULL, NULL);
  155 
  156 
  157 static uint8_t
  158 pmio_read(struct resource *res, uint8_t reg)
  159 {
  160         bus_write_1(res, 0, reg);       /* Index */
  161         return (bus_read_1(res, 1));    /* Data */
  162 }
  163 
  164 static void
  165 pmio_write(struct resource *res, uint8_t reg, uint8_t val)
  166 {
  167         bus_write_1(res, 0, reg);       /* Index */
  168         bus_write_1(res, 1, val);       /* Data */
  169 }
  170 
  171 static uint32_t
  172 wdctrl_read(struct amdsbwd_softc *sc)
  173 {
  174         return (bus_read_4(sc->res_ctrl, 0));
  175 }
  176 
  177 static void
  178 wdctrl_write(struct amdsbwd_softc *sc, uint32_t val)
  179 {
  180         bus_write_4(sc->res_ctrl, 0, val);
  181 }
  182 
  183 static __unused uint32_t
  184 wdcount_read(struct amdsbwd_softc *sc)
  185 {
  186         return (bus_read_4(sc->res_count, 0));
  187 }
  188 
  189 static void
  190 wdcount_write(struct amdsbwd_softc *sc, uint32_t val)
  191 {
  192         bus_write_4(sc->res_count, 0, val);
  193 }
  194 
  195 static void
  196 amdsbwd_tmr_enable(struct amdsbwd_softc *sc)
  197 {
  198         uint32_t val;
  199 
  200         val = wdctrl_read(sc);
  201         val |= AMDSB_WD_RUN;
  202         wdctrl_write(sc, val);
  203         sc->active = 1;
  204         amdsbwd_verbose_printf(sc->dev, "timer enabled\n");
  205 }
  206 
  207 static void
  208 amdsbwd_tmr_disable(struct amdsbwd_softc *sc)
  209 {
  210         uint32_t val;
  211 
  212         val = wdctrl_read(sc);
  213         val &= ~AMDSB_WD_RUN;
  214         wdctrl_write(sc, val);
  215         sc->active = 0;
  216         amdsbwd_verbose_printf(sc->dev, "timer disabled\n");
  217 }
  218 
  219 static void
  220 amdsbwd_tmr_reload(struct amdsbwd_softc *sc)
  221 {
  222         uint32_t val;
  223 
  224         val = wdctrl_read(sc);
  225         val |= AMDSB_WD_RELOAD;
  226         wdctrl_write(sc, val);
  227 }
  228 
  229 static void
  230 amdsbwd_tmr_set(struct amdsbwd_softc *sc, uint16_t timeout)
  231 {
  232 
  233         timeout &= AMDSB_WD_COUNT_MASK;
  234         wdcount_write(sc, timeout);
  235         sc->timeout = timeout;
  236         amdsbwd_verbose_printf(sc->dev, "timeout set to %u ticks\n", timeout);
  237 }
  238 
  239 static void
  240 amdsbwd_event(void *arg, unsigned int cmd, int *error)
  241 {
  242         struct amdsbwd_softc *sc = arg;
  243         unsigned int timeout;
  244 
  245         /* convert from power-of-two-ns to WDT ticks */
  246         cmd &= WD_INTERVAL;
  247         if (cmd < WD_TO_1SEC)
  248                 cmd = 0;
  249         if (cmd) {
  250                 timeout = ((uint64_t)1 << (cmd - WD_TO_1MS)) / sc->ms_per_tick;
  251                 if (timeout > sc->max_ticks)
  252                         timeout = sc->max_ticks;
  253                 if (timeout != sc->timeout) {
  254                         amdsbwd_tmr_set(sc, timeout);
  255                         if (!sc->active)
  256                                 amdsbwd_tmr_enable(sc);
  257                 }
  258                 amdsbwd_tmr_reload(sc);
  259                 *error = 0;
  260         } else {
  261                 if (sc->active)
  262                         amdsbwd_tmr_disable(sc);
  263         }
  264 }
  265 
  266 static void
  267 amdsbwd_identify(driver_t *driver, device_t parent)
  268 {
  269         device_t                child;
  270         device_t                smb_dev;
  271 
  272         if (resource_disabled("amdsbwd", 0))
  273                 return;
  274         if (device_find_child(parent, "amdsbwd", -1) != NULL)
  275                 return;
  276 
  277         /*
  278          * Try to identify SB600/SB7xx by PCI Device ID of SMBus device
  279          * that should be present at bus 0, device 20, function 0.
  280          */
  281         smb_dev = pci_find_bsf(0, 20, 0);
  282         if (smb_dev == NULL)
  283                 return;
  284         if (pci_get_devid(smb_dev) != AMDSB_SMBUS_DEVID &&
  285             pci_get_devid(smb_dev) != AMDHUDSON_SMBUS_DEVID &&
  286             pci_get_devid(smb_dev) != AMDKERNCZ_SMBUS_DEVID)
  287                 return;
  288 
  289         child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, "amdsbwd", -1);
  290         if (child == NULL)
  291                 device_printf(parent, "add amdsbwd child failed\n");
  292 }
  293 
  294 
  295 static void
  296 amdsbwd_probe_sb7xx(device_t dev, struct resource *pmres, uint32_t *addr)
  297 {
  298         uint32_t        val;
  299         int             i;
  300 
  301         /* Report cause of previous reset for user's convenience. */
  302         val = pmio_read(pmres, AMDSB_PM_RESET_STATUS0);
  303         if (val != 0)
  304                 amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val);
  305         val = pmio_read(pmres, AMDSB_PM_RESET_STATUS1);
  306         if (val != 0)
  307                 amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val);
  308         if ((val & AMDSB_WD_RST_STS) != 0)
  309                 device_printf(dev, "Previous Reset was caused by Watchdog\n");
  310 
  311         /* Find base address of memory mapped WDT registers. */
  312         for (*addr = 0, i = 0; i < 4; i++) {
  313                 *addr <<= 8;
  314                 *addr |= pmio_read(pmres, AMDSB_PM_WDT_BASE_MSB - i);
  315         }
  316         *addr &= ~0x07u;
  317 
  318         /* Set watchdog timer tick to 1s. */
  319         val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
  320         val &= ~AMDSB_WDT_RES_MASK;
  321         val |= AMDSB_WDT_RES_1S;
  322         pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
  323 
  324         /* Enable watchdog device (in stopped state). */
  325         val = pmio_read(pmres, AMDSB_PM_WDT_CTRL);
  326         val &= ~AMDSB_WDT_DISABLE;
  327         pmio_write(pmres, AMDSB_PM_WDT_CTRL, val);
  328 
  329         /*
  330          * XXX TODO: Ensure that watchdog decode is enabled
  331          * (register 0x41, bit 3).
  332          */
  333         device_set_desc(dev, "AMD SB600/SB7xx Watchdog Timer");
  334 }
  335 
  336 static void
  337 amdsbwd_probe_sb8xx(device_t dev, struct resource *pmres, uint32_t *addr)
  338 {
  339         uint32_t        val;
  340         int             i;
  341 
  342         /* Report cause of previous reset for user's convenience. */
  343         val = pmio_read(pmres, AMDSB8_PM_RESET_STATUS0);
  344         if (val != 0)
  345                 amdsbwd_verbose_printf(dev, "ResetStatus0 = %#04x\n", val);
  346         val = pmio_read(pmres, AMDSB8_PM_RESET_STATUS1);
  347         if (val != 0)
  348                 amdsbwd_verbose_printf(dev, "ResetStatus1 = %#04x\n", val);
  349         if ((val & AMDSB8_WD_RST_STS) != 0)
  350                 device_printf(dev, "Previous Reset was caused by Watchdog\n");
  351 
  352         /* Find base address of memory mapped WDT registers. */
  353         for (*addr = 0, i = 0; i < 4; i++) {
  354                 *addr <<= 8;
  355                 *addr |= pmio_read(pmres, AMDSB8_PM_WDT_EN + 3 - i);
  356         }
  357         *addr &= ~0x07u;
  358 
  359         /* Set watchdog timer tick to 1s. */
  360         val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
  361         val &= ~AMDSB8_WDT_RES_MASK;
  362         val |= AMDSB8_WDT_1HZ;
  363         pmio_write(pmres, AMDSB8_PM_WDT_CTRL, val);
  364 #ifdef AMDSBWD_DEBUG
  365         val = pmio_read(pmres, AMDSB8_PM_WDT_CTRL);
  366         amdsbwd_verbose_printf(dev, "AMDSB8_PM_WDT_CTRL value = %#02x\n", val);
  367 #endif
  368 
  369         /*
  370          * Enable watchdog device (in stopped state)
  371          * and decoding of its address.
  372          */
  373         val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
  374         val &= ~AMDSB8_WDT_DISABLE;
  375         val |= AMDSB8_WDT_DEC_EN;
  376         pmio_write(pmres, AMDSB8_PM_WDT_EN, val);
  377 #ifdef AMDSBWD_DEBUG
  378         val = pmio_read(pmres, AMDSB8_PM_WDT_EN);
  379         device_printf(dev, "AMDSB8_PM_WDT_EN value = %#02x\n", val);
  380 #endif
  381         device_set_desc(dev, "AMD SB8xx/SB9xx/Axx Watchdog Timer");
  382 }
  383 
  384 static int
  385 amdsbwd_probe(device_t dev)
  386 {
  387         struct resource         *res;
  388         device_t                smb_dev;
  389         uint32_t                addr;
  390         int                     rid;
  391         int                     rc;
  392 
  393         /* Do not claim some ISA PnP device by accident. */
  394         if (isa_get_logicalid(dev) != 0)
  395                 return (ENXIO);
  396 
  397         rc = bus_set_resource(dev, SYS_RES_IOPORT, 0, AMDSB_PMIO_INDEX,
  398             AMDSB_PMIO_WIDTH);
  399         if (rc != 0) {
  400                 device_printf(dev, "bus_set_resource for IO failed\n");
  401                 return (ENXIO);
  402         }
  403         rid = 0;
  404         res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
  405             RF_ACTIVE | RF_SHAREABLE);
  406         if (res == NULL) {
  407                 device_printf(dev, "bus_alloc_resource for IO failed\n");
  408                 return (ENXIO);
  409         }
  410 
  411         smb_dev = pci_find_bsf(0, 20, 0);
  412         KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
  413         if (pci_get_devid(smb_dev) == AMDSB_SMBUS_DEVID &&
  414             pci_get_revid(smb_dev) < AMDSB8_SMBUS_REVID)
  415                 amdsbwd_probe_sb7xx(dev, res, &addr);
  416         else
  417                 amdsbwd_probe_sb8xx(dev, res, &addr);
  418 
  419         bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
  420         bus_delete_resource(dev, SYS_RES_IOPORT, rid);
  421 
  422         amdsbwd_verbose_printf(dev, "memory base address = %#010x\n", addr);
  423         rc = bus_set_resource(dev, SYS_RES_MEMORY, 0, addr + AMDSB_WD_CTRL,
  424             AMDSB_WDIO_REG_WIDTH);
  425         if (rc != 0) {
  426                 device_printf(dev, "bus_set_resource for control failed\n");
  427                 return (ENXIO);
  428         }
  429         rc = bus_set_resource(dev, SYS_RES_MEMORY, 1, addr + AMDSB_WD_COUNT,
  430             AMDSB_WDIO_REG_WIDTH);
  431         if (rc != 0) {
  432                 device_printf(dev, "bus_set_resource for count failed\n");
  433                 return (ENXIO);
  434         }
  435 
  436         return (0);
  437 }
  438 
  439 static int
  440 amdsbwd_attach_sb(device_t dev, struct amdsbwd_softc *sc)
  441 {
  442         device_t        smb_dev;
  443 
  444         sc->max_ticks = UINT16_MAX;
  445         sc->rid_ctrl = 0;
  446         sc->rid_count = 1;
  447 
  448         smb_dev = pci_find_bsf(0, 20, 0);
  449         KASSERT(smb_dev != NULL, ("can't find SMBus PCI device\n"));
  450         sc->ms_per_tick = 1000;
  451 
  452         sc->res_ctrl = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  453             &sc->rid_ctrl, RF_ACTIVE);
  454         if (sc->res_ctrl == NULL) {
  455                 device_printf(dev, "bus_alloc_resource for ctrl failed\n");
  456                 return (ENXIO);
  457         }
  458         sc->res_count = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
  459             &sc->rid_count, RF_ACTIVE);
  460         if (sc->res_count == NULL) {
  461                 device_printf(dev, "bus_alloc_resource for count failed\n");
  462                 return (ENXIO);
  463         }
  464         return (0);
  465 }
  466 
  467 static int
  468 amdsbwd_attach(device_t dev)
  469 {
  470         struct amdsbwd_softc    *sc;
  471         int                     rc;
  472 
  473         sc = device_get_softc(dev);
  474         sc->dev = dev;
  475 
  476         rc = amdsbwd_attach_sb(dev, sc);
  477         if (rc != 0)
  478                 goto fail;
  479 
  480 #ifdef AMDSBWD_DEBUG
  481         device_printf(dev, "wd ctrl = %#04x\n", wdctrl_read(sc));
  482         device_printf(dev, "wd count = %#04x\n", wdcount_read(sc));
  483 #endif
  484 
  485         /* Setup initial state of Watchdog Control. */
  486         wdctrl_write(sc, AMDSB_WD_FIRED);
  487 
  488         if (wdctrl_read(sc) & AMDSB_WD_DISABLE) {
  489                 device_printf(dev, "watchdog hardware is disabled\n");
  490                 goto fail;
  491         }
  492 
  493         sc->ev_tag = EVENTHANDLER_REGISTER(watchdog_list, amdsbwd_event, sc,
  494             EVENTHANDLER_PRI_ANY);
  495 
  496         return (0);
  497 
  498 fail:
  499         amdsbwd_detach(dev);
  500         return (ENXIO);
  501 }
  502 
  503 static int
  504 amdsbwd_detach(device_t dev)
  505 {
  506         struct amdsbwd_softc *sc;
  507 
  508         sc = device_get_softc(dev);
  509         if (sc->ev_tag != NULL)
  510                 EVENTHANDLER_DEREGISTER(watchdog_list, sc->ev_tag);
  511 
  512         if (sc->active)
  513                 amdsbwd_tmr_disable(sc);
  514 
  515         if (sc->res_ctrl != NULL)
  516                 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_ctrl,
  517                     sc->res_ctrl);
  518 
  519         if (sc->res_count != NULL)
  520                 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid_count,
  521                     sc->res_count);
  522 
  523         return (0);
  524 }
  525 

Cache object: a0938cd9219d14c1c4ba25f5349084f7


[ 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.