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/pci/weasel_pci.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 /*      $NetBSD: weasel_pci.c,v 1.4 2002/10/02 16:52:00 thorpej Exp $   */
    2 
    3 /*-
    4  * Copyright (c) 2001 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Herb Peyerl and Jason Thorpe.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *        This product includes software developed by the NetBSD
   21  *        Foundation, Inc. and its contributors.
   22  * 4. Neither the name of The NetBSD Foundation nor the names of its
   23  *    contributors may be used to endorse or promote products derived
   24  *    from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   36  * POSSIBILITY OF SUCH DAMAGE.
   37  */
   38 
   39 /*
   40  * Device driver for the control space on the Middle Digital, Inc.
   41  * PCI-Weasel serial console board.
   42  *
   43  * Since the other functions of the PCI-Weasel already appear in
   44  * PCI configuration space, we just need to hook up the watchdog
   45  * timer.
   46  */
   47 
   48 #include <sys/cdefs.h>
   49 __KERNEL_RCSID(0, "$NetBSD: weasel_pci.c,v 1.4 2002/10/02 16:52:00 thorpej Exp $");
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/device.h>
   54 #include <sys/wdog.h>
   55 #include <sys/endian.h>
   56 
   57 #include <machine/bus.h>
   58 
   59 #include <dev/pci/pcireg.h>
   60 #include <dev/pci/pcivar.h>
   61 #include <dev/pci/pcidevs.h>
   62 
   63 #include <dev/pci/weaselreg.h>
   64 
   65 #include <dev/sysmon/sysmonvar.h>
   66 
   67 struct weasel_softc {
   68         struct device sc_dev;           /* generic device glue */
   69 
   70         bus_space_tag_t sc_st;
   71         bus_space_handle_t sc_sh;
   72 
   73         struct sysmon_wdog sc_smw;
   74 
   75         int sc_wdog_armed;
   76         int sc_wdog_period;
   77 };
   78 
   79 int     weasel_pci_match(struct device *, struct cfdata *, void *);
   80 void    weasel_pci_attach(struct device *, struct device *, void *);
   81 extern int      sysmon_wdog_setmode(struct sysmon_wdog *, int, u_int);
   82 
   83 CFATTACH_DECL(weasel_pci, sizeof(struct weasel_softc),
   84     weasel_pci_match, weasel_pci_attach, NULL, NULL);
   85 
   86 int     weasel_pci_wdog_setmode(struct sysmon_wdog *);
   87 int     weasel_pci_wdog_tickle(struct sysmon_wdog *);
   88 
   89 int     weasel_wait_response(struct weasel_softc *);
   90 int     weasel_issue_command(struct weasel_softc *, uint8_t cmd);
   91 
   92 int     weasel_pci_wdog_arm(struct weasel_softc *);
   93 int     weasel_pci_wdog_disarm(struct weasel_softc *);
   94 
   95 int     weasel_pci_wdog_query_state(struct weasel_softc *);
   96 
   97 int
   98 weasel_pci_match(struct device *parent, struct cfdata *cf, void *aux)
   99 {
  100         struct pci_attach_args *pa = aux;
  101 
  102         if (PCI_VENDOR(pa->pa_id) == PCI_VENDOR_MIDDLE_DIGITAL &&
  103             PCI_PRODUCT(pa->pa_id) == PCI_PRODUCT_MIDDLE_DIGITAL_WEASEL_CONTROL)
  104                 return (1);
  105 
  106         return (0);
  107 }
  108 
  109 void
  110 weasel_pci_attach(struct device *parent, struct device *self, void *aux)
  111 {
  112         struct weasel_softc *sc = (void *) self;
  113         struct pci_attach_args *pa = aux;
  114         struct weasel_config_block cfg;
  115         const char *vers, *mode;
  116         uint8_t v, *cp;
  117         uint16_t cfg_size;
  118         uint8_t buf[8];
  119 
  120         printf(": PCI-Weasel watchdog timer\n");
  121 
  122         if (pci_mapreg_map(pa, PCI_MAPREG_START,
  123             PCI_MAPREG_TYPE_MEM|PCI_MAPREG_MEM_TYPE_32BIT, 0,
  124             &sc->sc_st, &sc->sc_sh, NULL, NULL) != 0) {
  125                 printf("%s: unable to map device registers\n",
  126                     sc->sc_dev.dv_xname);
  127                 return;
  128         }
  129 
  130         /* Ping the Weasel to see if it's alive. */
  131         if (weasel_issue_command(sc, OS_CMD_PING)) {
  132                 printf("%s: Weasel didn't respond to PING\n",
  133                     sc->sc_dev.dv_xname);
  134                 return;
  135         }
  136         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  137         if ((v = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD)) !=
  138             OS_RET_PONG) {
  139                 printf("%s: unexpected PING response from Weasel: 0x%02x\n",
  140                     sc->sc_dev.dv_xname, v);
  141                 return;
  142         }
  143 
  144         /* Read the config block. */
  145         if (weasel_issue_command(sc, OS_CMD_SHOW_CONFIG)) {
  146                 printf("%s: Weasel didn't respond to SHOW_CONFIG\n",
  147                     sc->sc_dev.dv_xname);
  148                 return;
  149         }
  150         cfg_size = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  151         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  152 
  153         if (++cfg_size != sizeof(cfg)) {
  154                 printf("%s: weird config block size from Weasel: 0x%03x\n",
  155                     sc->sc_dev.dv_xname, cfg_size);
  156                 return;
  157         }
  158 
  159         for (cp = (uint8_t *) &cfg; cfg_size != 0; cfg_size--) {
  160                 if (weasel_wait_response(sc)) {
  161                         printf("%s: Weasel stopped providing config block(%d)\n",
  162                             sc->sc_dev.dv_xname, cfg_size);
  163                         return;
  164                 }
  165                 *cp++ = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  166                 bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  167         }
  168 
  169         switch (cfg.cfg_version) {
  170         case CFG_VERSION_2:
  171                 vers="2";
  172                 switch (cfg.enable_duart_switching) {
  173                 case 0:
  174                         mode = "emulation";
  175                         break;
  176                 case 1:
  177                         mode = "serial";
  178                         break;
  179                 case 2:
  180                         mode = "autoswitch";
  181                         break;
  182                 default:
  183                         mode = "unknown";
  184                 }
  185                 break;
  186 
  187         default:
  188                 vers = mode = NULL;
  189         }
  190 
  191         if (vers != NULL)
  192                 printf("%s: %s mode\n", sc->sc_dev.dv_xname,
  193                     mode);
  194         else
  195                 printf("%s: unknown config version 0x%02x\n", sc->sc_dev.dv_xname,
  196                     cfg.cfg_version);
  197         
  198         /*
  199          * Fetch sw version.
  200          */
  201         if (weasel_issue_command(sc, OS_CMD_QUERY_SW_VER)) {
  202                 printf("%s: didn't reply to software version query.\n", 
  203                         sc->sc_dev.dv_xname);
  204         }
  205         else {
  206                 v = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  207                 bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  208                 if (v>7)
  209                         printf("%s: weird length for version string(%d).\n", 
  210                                         sc->sc_dev.dv_xname, v);
  211                 bzero(buf, sizeof(buf));
  212                 for (cp = buf; v != 0; v--) {
  213                         if (weasel_wait_response(sc)) {
  214                                 printf("%s: Weasel stopped providing version\n",
  215                                     sc->sc_dev.dv_xname);
  216                         }
  217                         *cp++ = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  218                         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  219                 }
  220                 printf("%s: sw: %s", sc->sc_dev.dv_xname, buf);
  221         }
  222         /*
  223          * Fetch logic version.
  224          */
  225         if (weasel_issue_command(sc, OS_CMD_QUERY_L_VER)) {
  226                 printf("\n%s: didn't reply to logic version query.\n", 
  227                         sc->sc_dev.dv_xname);
  228         }
  229         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  230         v = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  231         printf(" logic: %03d", v);
  232         /*
  233          * Fetch vga bios version.
  234          */
  235         if (weasel_issue_command(sc, OS_CMD_QUERY_VB_VER)) {
  236                 printf("\n%s: didn't reply to vga bios version query.\n", 
  237                         sc->sc_dev.dv_xname);
  238         }
  239         v = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  240         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  241         printf(" vga bios: %d.%d", (v>>4), (v&0x0f));
  242         /*
  243          * Fetch hw version.
  244          */
  245         if (weasel_issue_command(sc, OS_CMD_QUERY_HW_VER)) {
  246                 printf("\n%s: didn't reply to hardware version query.\n", 
  247                         sc->sc_dev.dv_xname);
  248         }
  249         v = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  250         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  251         printf(" hw: %d.%d", (v>>4), (v&0x0f));
  252 
  253         printf("\n%s: break passthrough %s", sc->sc_dev.dv_xname,
  254             cfg.break_passthru ? "enabled" : "disabled");
  255         
  256         if ((sc->sc_wdog_armed = weasel_pci_wdog_query_state(sc)) == -1)
  257                 sc->sc_wdog_armed = 0;
  258         
  259         /* Weasel is big-endian */
  260         sc->sc_wdog_period = be16toh(cfg.wdt_msec) / 1000;
  261 
  262         printf(", watchdog timer %d sec.\n", sc->sc_wdog_period);
  263         sc->sc_smw.smw_name = "weasel";
  264         sc->sc_smw.smw_cookie = sc;
  265         sc->sc_smw.smw_setmode = weasel_pci_wdog_setmode;
  266         sc->sc_smw.smw_tickle = weasel_pci_wdog_tickle;
  267         sc->sc_smw.smw_period = sc->sc_wdog_period;
  268 
  269         if (sysmon_wdog_register(&sc->sc_smw) != 0)
  270                 printf("%s: unable to register PC-Weasel watchdog "
  271                     "with sysmon\n", sc->sc_dev.dv_xname);
  272 }
  273 
  274 int
  275 weasel_wait_response(struct weasel_softc *sc)
  276 {
  277         int i;
  278 
  279         for (i = 10000; i ; i--) {
  280                 delay(100);
  281                 if (bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS) ==
  282                     OS_WS_HOST_READ)
  283                         return(0);
  284         }
  285         return (1);
  286 }
  287 
  288 int
  289 weasel_issue_command(struct weasel_softc *sc, uint8_t cmd)
  290 {
  291         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_WR, cmd);
  292         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_HOST_STATUS, OS_HS_WEASEL_READ);
  293         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  294         return (weasel_wait_response(sc));
  295 }
  296 
  297 int
  298 weasel_pci_wdog_setmode(struct sysmon_wdog *smw)
  299 {
  300         struct weasel_softc *sc = smw->smw_cookie;
  301         int error = 0;
  302 
  303         if ((smw->smw_mode & WDOG_MODE_MASK) == WDOG_MODE_DISARMED) {
  304                 error = weasel_pci_wdog_disarm(sc);
  305         } else {
  306                 if (smw->smw_period == WDOG_PERIOD_DEFAULT)
  307                         smw->smw_period = sc->sc_wdog_period;
  308                 else if (smw->smw_period != sc->sc_wdog_period) {
  309                         /* Can't change the period on the Weasel. */
  310                         return (EINVAL);
  311                 }
  312                 error = weasel_pci_wdog_arm(sc);
  313                 weasel_pci_wdog_tickle(smw);
  314         }
  315 
  316         return (error);
  317 }
  318 
  319 int
  320 weasel_pci_wdog_tickle(struct sysmon_wdog *smw)
  321 {
  322         struct weasel_softc *sc = smw->smw_cookie; 
  323         u_int8_t reg;
  324         int x;
  325         int s;
  326         int error = 0;
  327 
  328         s = splhigh();
  329         /*
  330          * first we tickle the watchdog
  331          */
  332         reg = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_CHALLENGE);
  333         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_RESPONSE, ~reg);
  334 
  335         /*
  336          * then we check to make sure the weasel is still armed. If someone
  337          * has rebooted the weasel for whatever reason (firmware update),
  338          * then the watchdog timer would no longer be armed and we'd be 
  339          * servicing nothing. Let the user know that the machine is no
  340          * longer being monitored by the weasel.
  341          */
  342         if((x = weasel_pci_wdog_query_state(sc)) == -1)
  343                 error = EIO;
  344         if (x == 1) { 
  345                 error = 0;
  346         } else {
  347                 printf("%s: Watchdog timer disabled on PC/Weasel! Disarming wdog.\n", 
  348                         sc->sc_dev.dv_xname);
  349                 sc->sc_wdog_armed = 0;
  350                 sysmon_wdog_setmode(smw, WDOG_MODE_DISARMED, 0);
  351                 error = 1;
  352         }
  353         splx(s);
  354 
  355         return (error);
  356 }
  357 
  358 int
  359 weasel_pci_wdog_arm(struct weasel_softc *sc)
  360 {
  361         u_int8_t reg;
  362         int x;
  363         int s;
  364         int error = 0;
  365 
  366         s = splhigh();
  367         if (weasel_issue_command(sc, OS_CMD_WDT_ENABLE)) {
  368                 printf("%s: no reply to watchdog enable. Check Weasel \"Allow Watchdog\" setting.\n", 
  369                         sc->sc_dev.dv_xname);
  370                 error = EIO;
  371         }
  372         reg = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  373         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  374 
  375         /*
  376          * Ensure that the Weasel thinks it's in the same mode we want it to
  377          * be in.   EIO if not.
  378          */
  379         x = weasel_pci_wdog_query_state(sc);
  380         switch (x) {
  381                 case -1:
  382                         error = EIO;
  383                         break;
  384                 case 0: 
  385                         sc->sc_wdog_armed = 0;
  386                         error = EIO;
  387                         break;
  388                 case 1:
  389                         sc->sc_wdog_armed = 1;
  390                         error = 0;
  391                         break;
  392         }
  393                                 
  394         splx(s);
  395         return(error);
  396 }
  397 
  398 
  399 int
  400 weasel_pci_wdog_disarm(struct weasel_softc *sc)
  401 {
  402         u_int8_t reg;
  403         int x;
  404         int s;
  405         int error = 0;
  406 
  407         s = splhigh();
  408 
  409         if (weasel_issue_command(sc, OS_CMD_WDT_DISABLE)) {
  410                 printf("%s: didn't reply to watchdog disable.\n", 
  411                         sc->sc_dev.dv_xname);
  412                 error = EIO;
  413         }
  414         reg = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  415         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  416 
  417         /*
  418          * Ensure that the Weasel thinks it's in the same mode we want it to
  419          * be in.   EIO if not.
  420          */
  421         x = weasel_pci_wdog_query_state(sc);
  422         switch (x) {
  423                 case -1:
  424                         error = EIO;
  425                         break;
  426                 case 0: 
  427                         sc->sc_wdog_armed = 0;
  428                         error = 0;
  429                         break;
  430                 case 1:
  431                         sc->sc_wdog_armed = 1;
  432                         error = EIO;
  433                         break;
  434         }
  435                                 
  436         splx(s);
  437         return(error);
  438 }
  439 
  440 int
  441 weasel_pci_wdog_query_state(struct weasel_softc *sc)
  442 {
  443 
  444         u_int8_t v;
  445 
  446         if (weasel_issue_command(sc, OS_CMD_WDT_QUERY)) {
  447                 printf("%s: didn't reply to watchdog state query.\n", 
  448                         sc->sc_dev.dv_xname);
  449                 bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  450                 return(-1);
  451         }
  452         v = bus_space_read_1(sc->sc_st, sc->sc_sh, WEASEL_DATA_RD);
  453         bus_space_write_1(sc->sc_st, sc->sc_sh, WEASEL_STATUS, 0);
  454         return(v);
  455 }

Cache object: abeb590624c8c02f35b85d407509a642


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