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/sparc64/pci/sbbc.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 /*      $OpenBSD: sbbc.c,v 1.7 2009/11/09 17:53:39 nicm Exp $   */
    2 /*-
    3  * Copyright (c) 2008 Mark Kettenis
    4  *
    5  * Permission to use, copy, modify, and distribute this software for any
    6  * purpose with or without fee is hereby granted, provided that the above
    7  * copyright notice and this permission notice appear in all copies.
    8  *
    9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16  */
   17 /*-
   18  * Copyright (c) 2010 Marius Strobl <marius@FreeBSD.org>
   19  * All rights reserved.
   20  *
   21  * Redistribution and use in source and binary forms, with or without
   22  * modification, are permitted provided that the following conditions
   23  * are met:
   24  * 1. Redistributions of source code must retain the above copyright
   25  *    notice, this list of conditions and the following disclaimer.
   26  * 2. Redistributions in binary form must reproduce the above copyright
   27  *    notice, this list of conditions and the following disclaimer in the
   28  *    documentation and/or other materials provided with the distribution.
   29  *
   30  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   31  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   32  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   33  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   34  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   35  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   36  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   37  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   38  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   39  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   40  * SUCH DAMAGE.
   41  */
   42 
   43 #include <sys/cdefs.h>
   44 __FBSDID("$FreeBSD$");
   45 
   46 #include <sys/param.h>
   47 #include <sys/systm.h>
   48 #include <sys/bus.h>
   49 #include <sys/clock.h>
   50 #include <sys/endian.h>
   51 #include <sys/kernel.h>
   52 #include <sys/lock.h>
   53 #include <sys/module.h>
   54 #include <sys/mutex.h>
   55 #include <sys/resource.h>
   56 #include <sys/rman.h>
   57 
   58 #include <dev/ofw/ofw_bus.h>
   59 #include <dev/ofw/openfirm.h>
   60 
   61 #include <machine/bus.h>
   62 #include <machine/cpu.h>
   63 #include <machine/resource.h>
   64 
   65 #include <dev/pci/pcireg.h>
   66 #include <dev/pci/pcivar.h>
   67 #include <dev/uart/uart.h>
   68 #include <dev/uart/uart_cpu.h>
   69 #include <dev/uart/uart_bus.h>
   70 
   71 #include "clock_if.h"
   72 #include "uart_if.h"
   73 
   74 #define SBBC_PCI_BAR            PCIR_BAR(0)
   75 #define SBBC_PCI_VENDOR         0x108e
   76 #define SBBC_PCI_PRODUCT        0xc416
   77 
   78 #define SBBC_REGS_OFFSET        0x800000
   79 #define SBBC_REGS_SIZE          0x6230
   80 #define SBBC_EPLD_OFFSET        0x8e0000
   81 #define SBBC_EPLD_SIZE          0x20
   82 #define SBBC_SRAM_OFFSET        0x900000
   83 #define SBBC_SRAM_SIZE          0x20000 /* 128KB SRAM */
   84 
   85 #define SBBC_PCI_INT_STATUS     0x2320
   86 #define SBBC_PCI_INT_ENABLE     0x2330
   87 #define SBBC_PCI_ENABLE_INT_A   0x11
   88 
   89 #define SBBC_EPLD_INTERRUPT     0x13
   90 #define SBBC_EPLD_INTERRUPT_ON  0x01
   91 
   92 #define SBBC_SRAM_CONS_IN               0x00000001
   93 #define SBBC_SRAM_CONS_OUT              0x00000002
   94 #define SBBC_SRAM_CONS_BRK              0x00000004
   95 #define SBBC_SRAM_CONS_SPACE_IN         0x00000008
   96 #define SBBC_SRAM_CONS_SPACE_OUT        0x00000010
   97 
   98 #define SBBC_TAG_KEY_SIZE       8
   99 #define SBBC_TAG_KEY_SCSOLIE    "SCSOLIE"       /* SC -> OS int. enable */
  100 #define SBBC_TAG_KEY_SCSOLIR    "SCSOLIR"       /* SC -> OS int. reason */
  101 #define SBBC_TAG_KEY_SOLCONS    "SOLCONS"       /* OS console buffer */
  102 #define SBBC_TAG_KEY_SOLSCIE    "SOLSCIE"       /* OS -> SC int. enable */
  103 #define SBBC_TAG_KEY_SOLSCIR    "SOLSCIR"       /* OS -> SC int. reason */
  104 #define SBBC_TAG_KEY_TODDATA    "TODDATA"       /* OS TOD struct */
  105 #define SBBC_TAG_OFF(x)         offsetof(struct sbbc_sram_tag, x)
  106 
  107 struct sbbc_sram_tag {
  108         char            tag_key[SBBC_TAG_KEY_SIZE];
  109         uint32_t        tag_size;
  110         uint32_t        tag_offset;
  111 } __packed;
  112 
  113 #define SBBC_TOC_MAGIC          "TOCSRAM"
  114 #define SBBC_TOC_MAGIC_SIZE     8
  115 #define SBBC_TOC_TAGS_MAX       32
  116 #define SBBC_TOC_OFF(x)         offsetof(struct sbbc_sram_toc, x)
  117 
  118 struct sbbc_sram_toc {
  119         char                    toc_magic[SBBC_TOC_MAGIC_SIZE];
  120         uint8_t                 toc_reserved;
  121         uint8_t                 toc_type;
  122         uint16_t                toc_version;
  123         uint32_t                toc_ntags;
  124         struct sbbc_sram_tag    toc_tag[SBBC_TOC_TAGS_MAX];
  125 } __packed;
  126 
  127 #define SBBC_TOD_MAGIC          0x54443100      /* "TD1" */
  128 #define SBBC_TOD_VERSION        1
  129 #define SBBC_TOD_OFF(x)         offsetof(struct sbbc_sram_tod, x)
  130 
  131 struct sbbc_sram_tod {
  132         uint32_t        tod_magic;
  133         uint32_t        tod_version;
  134         uint64_t        tod_time;
  135         uint64_t        tod_skew;
  136         uint32_t        tod_reserved;
  137         uint32_t        tod_heartbeat;
  138         uint32_t        tod_timeout;
  139 } __packed;
  140 
  141 #define SBBC_CONS_MAGIC         0x434f4e00      /* "CON" */
  142 #define SBBC_CONS_VERSION       1
  143 #define SBBC_CONS_OFF(x)        offsetof(struct sbbc_sram_cons, x)
  144 
  145 struct sbbc_sram_cons {
  146         uint32_t cons_magic;
  147         uint32_t cons_version;
  148         uint32_t cons_size;
  149 
  150         uint32_t cons_in_begin;
  151         uint32_t cons_in_end;
  152         uint32_t cons_in_rdptr;
  153         uint32_t cons_in_wrptr;
  154 
  155         uint32_t cons_out_begin;
  156         uint32_t cons_out_end;
  157         uint32_t cons_out_rdptr;
  158         uint32_t cons_out_wrptr;
  159 } __packed;
  160 
  161 struct sbbc_softc {
  162         struct resource *sc_res;
  163 };
  164 
  165 #define SBBC_READ_N(wdth, offs)                                         \
  166         bus_space_read_ ## wdth((bst), (bsh), (offs))
  167 #define SBBC_WRITE_N(wdth, offs, val)                                   \
  168         bus_space_write_ ## wdth((bst), (bsh), (offs), (val))
  169 
  170 #define SBBC_READ_1(offs)                                               \
  171         SBBC_READ_N(1, (offs))
  172 #define SBBC_READ_2(offs)                                               \
  173         bswap16(SBBC_READ_N(2, (offs)))
  174 #define SBBC_READ_4(offs)                                               \
  175         bswap32(SBBC_READ_N(4, (offs)))
  176 #define SBBC_READ_8(offs)                                               \
  177         bswap64(SBBC_READ_N(8, (offs)))
  178 #define SBBC_WRITE_1(offs, val)                                         \
  179         SBBC_WRITE_N(1, (offs), (val))
  180 #define SBBC_WRITE_2(offs, val)                                         \
  181         SBBC_WRITE_N(2, (offs), bswap16(val))
  182 #define SBBC_WRITE_4(offs, val)                                         \
  183         SBBC_WRITE_N(4, (offs), bswap32(val))
  184 #define SBBC_WRITE_8(offs, val)                                         \
  185         SBBC_WRITE_N(8, (offs), bswap64(val))
  186 
  187 #define SBBC_REGS_READ_1(offs)                                          \
  188         SBBC_READ_1((offs) + SBBC_REGS_OFFSET)
  189 #define SBBC_REGS_READ_2(offs)                                          \
  190         SBBC_READ_2((offs) + SBBC_REGS_OFFSET)
  191 #define SBBC_REGS_READ_4(offs)                                          \
  192         SBBC_READ_4((offs) + SBBC_REGS_OFFSET)
  193 #define SBBC_REGS_READ_8(offs)                                          \
  194         SBBC_READ_8((offs) + SBBC_REGS_OFFSET)
  195 #define SBBC_REGS_WRITE_1(offs, val)                                    \
  196         SBBC_WRITE_1((offs) + SBBC_REGS_OFFSET, (val))
  197 #define SBBC_REGS_WRITE_2(offs, val)                                    \
  198         SBBC_WRITE_2((offs) + SBBC_REGS_OFFSET, (val))
  199 #define SBBC_REGS_WRITE_4(offs, val)                                    \
  200         SBBC_WRITE_4((offs) + SBBC_REGS_OFFSET, (val))
  201 #define SBBC_REGS_WRITE_8(offs, val)                                    \
  202         SBBC_WRITE_8((offs) + SBBC_REGS_OFFSET, (val))
  203 
  204 #define SBBC_EPLD_READ_1(offs)                                          \
  205         SBBC_READ_1((offs) + SBBC_EPLD_OFFSET)
  206 #define SBBC_EPLD_READ_2(offs)                                          \
  207         SBBC_READ_2((offs) + SBBC_EPLD_OFFSET)
  208 #define SBBC_EPLD_READ_4(offs)                                          \
  209         SBBC_READ_4((offs) + SBBC_EPLD_OFFSET)
  210 #define SBBC_EPLD_READ_8(offs)                                          \
  211         SBBC_READ_8((offs) + SBBC_EPLD_OFFSET)
  212 #define SBBC_EPLD_WRITE_1(offs, val)                                    \
  213         SBBC_WRITE_1((offs) + SBBC_EPLD_OFFSET, (val))
  214 #define SBBC_EPLD_WRITE_2(offs, val)                                    \
  215         SBBC_WRITE_2((offs) + SBBC_EPLD_OFFSET, (val))
  216 #define SBBC_EPLD_WRITE_4(offs, val)                                    \
  217         SBBC_WRITE_4((offs) + SBBC_EPLD_OFFSET, (val))
  218 #define SBBC_EPLD_WRITE_8(offs, val)                                    \
  219         SBBC_WRITE_8((offs) + SBBC_EPLD_OFFSET, (val))
  220 
  221 #define SBBC_SRAM_READ_1(offs)                                          \
  222         SBBC_READ_1((offs) + SBBC_SRAM_OFFSET)
  223 #define SBBC_SRAM_READ_2(offs)                                          \
  224         SBBC_READ_2((offs) + SBBC_SRAM_OFFSET)
  225 #define SBBC_SRAM_READ_4(offs)                                          \
  226         SBBC_READ_4((offs) + SBBC_SRAM_OFFSET)
  227 #define SBBC_SRAM_READ_8(offs)                                          \
  228         SBBC_READ_8((offs) + SBBC_SRAM_OFFSET)
  229 #define SBBC_SRAM_WRITE_1(offs, val)                                    \
  230         SBBC_WRITE_1((offs) + SBBC_SRAM_OFFSET, (val))
  231 #define SBBC_SRAM_WRITE_2(offs, val)                                    \
  232         SBBC_WRITE_2((offs) + SBBC_SRAM_OFFSET, (val))
  233 #define SBBC_SRAM_WRITE_4(offs, val)                                    \
  234         SBBC_WRITE_4((offs) + SBBC_SRAM_OFFSET, (val))
  235 #define SBBC_SRAM_WRITE_8(offs, val)                                    \
  236         SBBC_WRITE_8((offs) + SBBC_SRAM_OFFSET, (val))
  237 
  238 #define SUNW_SETCONSINPUT       "SUNW,set-console-input"
  239 #define SUNW_SETCONSINPUT_CLNT  "CON_CLNT"
  240 #define SUNW_SETCONSINPUT_OBP   "CON_OBP"
  241 
  242 static u_int sbbc_console;
  243 
  244 static uint32_t sbbc_scsolie;
  245 static uint32_t sbbc_scsolir;
  246 static uint32_t sbbc_solcons;
  247 static uint32_t sbbc_solscie;
  248 static uint32_t sbbc_solscir;
  249 static uint32_t sbbc_toddata;
  250 
  251 /*
  252  * internal helpers
  253  */
  254 static int sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh);
  255 static inline void sbbc_send_intr(bus_space_tag_t bst,
  256     bus_space_handle_t bsh);
  257 static const char *sbbc_serengeti_set_console_input(char *new);
  258 
  259 /*
  260  * SBBC PCI interface
  261  */
  262 static bus_activate_resource_t sbbc_bus_activate_resource;
  263 static bus_adjust_resource_t sbbc_bus_adjust_resource;
  264 static bus_deactivate_resource_t sbbc_bus_deactivate_resource;
  265 static bus_alloc_resource_t sbbc_bus_alloc_resource;
  266 static bus_release_resource_t sbbc_bus_release_resource;
  267 static bus_get_resource_list_t sbbc_bus_get_resource_list;
  268 static bus_setup_intr_t sbbc_bus_setup_intr;
  269 static bus_teardown_intr_t sbbc_bus_teardown_intr;
  270 
  271 static device_attach_t sbbc_pci_attach;
  272 static device_probe_t sbbc_pci_probe;
  273 
  274 static clock_gettime_t sbbc_tod_gettime;
  275 static clock_settime_t sbbc_tod_settime;
  276 
  277 static device_method_t sbbc_pci_methods[] = {
  278         /* Device interface */
  279         DEVMETHOD(device_probe,         sbbc_pci_probe),
  280         DEVMETHOD(device_attach,        sbbc_pci_attach),
  281 
  282         DEVMETHOD(bus_alloc_resource,   sbbc_bus_alloc_resource),
  283         DEVMETHOD(bus_activate_resource,sbbc_bus_activate_resource),
  284         DEVMETHOD(bus_deactivate_resource,sbbc_bus_deactivate_resource),
  285         DEVMETHOD(bus_adjust_resource,  sbbc_bus_adjust_resource),
  286         DEVMETHOD(bus_release_resource, sbbc_bus_release_resource),
  287         DEVMETHOD(bus_setup_intr,       sbbc_bus_setup_intr),
  288         DEVMETHOD(bus_teardown_intr,    sbbc_bus_teardown_intr),
  289         DEVMETHOD(bus_get_resource,     bus_generic_rl_get_resource),
  290         DEVMETHOD(bus_get_resource_list, sbbc_bus_get_resource_list),
  291 
  292         /* clock interface */
  293         DEVMETHOD(clock_gettime,        sbbc_tod_gettime),
  294         DEVMETHOD(clock_settime,        sbbc_tod_settime),
  295 
  296         DEVMETHOD_END
  297 };
  298 
  299 static devclass_t sbbc_devclass;
  300 
  301 DEFINE_CLASS_0(sbbc, sbbc_driver, sbbc_pci_methods, sizeof(struct sbbc_softc));
  302 DRIVER_MODULE(sbbc, pci, sbbc_driver, sbbc_devclass, NULL, NULL);
  303 
  304 static int
  305 sbbc_pci_probe(device_t dev)
  306 {
  307 
  308         if (pci_get_vendor(dev) == SBBC_PCI_VENDOR &&
  309             pci_get_device(dev) == SBBC_PCI_PRODUCT) {
  310                 device_set_desc(dev, "Sun BootBus controller");
  311                 return (BUS_PROBE_DEFAULT);
  312         }
  313         return (ENXIO);
  314 }
  315 
  316 static int
  317 sbbc_pci_attach(device_t dev)
  318 {
  319         struct sbbc_softc *sc;
  320         struct timespec ts;
  321         device_t child;
  322         bus_space_tag_t bst;
  323         bus_space_handle_t bsh;
  324         phandle_t node;
  325         int error, rid;
  326         uint32_t val;
  327 
  328         /* Nothing to to if we're not the chosen one. */
  329         if ((node = OF_finddevice("/chosen")) == -1) {
  330                 device_printf(dev, "failed to find /chosen\n");
  331                 return (ENXIO);
  332         }
  333         if (OF_getprop(node, "iosram", &node, sizeof(node)) == -1) {
  334                 device_printf(dev, "failed to get iosram\n");
  335                 return (ENXIO);
  336         }
  337         if (node != ofw_bus_get_node(dev))
  338                 return (0);
  339 
  340         sc = device_get_softc(dev);
  341         rid = SBBC_PCI_BAR;
  342         sc->sc_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid,
  343             RF_ACTIVE);
  344         if (sc->sc_res == NULL) {
  345                 device_printf(dev, "failed to allocate resources\n");
  346                 return (ENXIO);
  347         }
  348         bst = rman_get_bustag(sc->sc_res);
  349         bsh = rman_get_bushandle(sc->sc_res);
  350         if (sbbc_console != 0) {
  351                 /* Once again the interrupt pin isn't set. */
  352                 if (pci_get_intpin(dev) == 0)
  353                         pci_set_intpin(dev, 1);
  354                 child = device_add_child(dev, NULL, -1);
  355                 if (child == NULL)
  356                         device_printf(dev, "failed to add UART device\n");
  357                 error = bus_generic_attach(dev);
  358                 if (error != 0)
  359                         device_printf(dev, "failed to attach UART device\n");
  360         } else {
  361                 error = sbbc_parse_toc(bst, bsh);
  362                 if (error != 0) {
  363                         device_printf(dev, "failed to parse TOC\n");
  364                         if (sbbc_console != 0) {
  365                                 bus_release_resource(dev, SYS_RES_MEMORY, rid,
  366                                     sc->sc_res);
  367                                 return (error);
  368                         }
  369                 }
  370         }
  371         if (sbbc_toddata != 0) {
  372                 if ((val = SBBC_SRAM_READ_4(sbbc_toddata +
  373                     SBBC_TOD_OFF(tod_magic))) != SBBC_TOD_MAGIC)
  374                         device_printf(dev, "invalid TOD magic %#x\n", val);
  375                 else if ((val = SBBC_SRAM_READ_4(sbbc_toddata +
  376                     SBBC_TOD_OFF(tod_version))) < SBBC_TOD_VERSION)
  377                         device_printf(dev, "invalid TOD version %#x\n", val);
  378                 else {
  379                         clock_register(dev, 1000000); /* 1 sec. resolution */
  380                         if (bootverbose) {
  381                                 sbbc_tod_gettime(dev, &ts);
  382                                 device_printf(dev,
  383                                     "current time: %ld.%09ld\n",
  384                                     (long)ts.tv_sec, ts.tv_nsec);
  385                         }
  386                 }
  387         }
  388         return (0);
  389 }
  390 
  391 /*
  392  * Note that the bus methods don't pass-through the uart(4) requests but act
  393  * as if they would come from sbbc(4) in order to avoid complications with
  394  * pci(4) (actually, uart(4) isn't a real child but rather a function of
  395  * sbbc(4) anyway).
  396  */
  397 
  398 static struct resource *
  399 sbbc_bus_alloc_resource(device_t dev, device_t child __unused, int type,
  400     int *rid, u_long start, u_long end, u_long count, u_int flags)
  401 {
  402         struct sbbc_softc *sc;
  403 
  404         sc = device_get_softc(dev);
  405         switch (type) {
  406         case SYS_RES_IRQ:
  407                 return (bus_generic_alloc_resource(dev, dev, type, rid, start,
  408                     end, count, flags));
  409         case SYS_RES_MEMORY:
  410                 return (sc->sc_res);
  411         default:
  412                 return (NULL);
  413         }
  414 }
  415 
  416 static int
  417 sbbc_bus_activate_resource(device_t bus, device_t child, int type, int rid,
  418     struct resource *res)
  419 {
  420 
  421         if (type == SYS_RES_MEMORY)
  422                 return (0);
  423         return (bus_generic_activate_resource(bus, child, type, rid, res));
  424 }
  425 
  426 static int
  427 sbbc_bus_deactivate_resource(device_t bus, device_t child, int type, int rid,
  428     struct resource *res)
  429 {
  430 
  431         if (type == SYS_RES_MEMORY)
  432                 return (0);
  433         return (bus_generic_deactivate_resource(bus, child, type, rid, res));
  434 }
  435 
  436 static int
  437 sbbc_bus_adjust_resource(device_t bus __unused, device_t child __unused,
  438     int type __unused, struct resource *res __unused, u_long start __unused,
  439     u_long end __unused)
  440 {
  441 
  442         return (ENXIO);
  443 }
  444 
  445 static int
  446 sbbc_bus_release_resource(device_t dev, device_t child __unused, int type,
  447     int rid, struct resource *res)
  448 {
  449 
  450         if (type == SYS_RES_IRQ)
  451                 return (bus_generic_release_resource(dev, dev, type, rid,
  452                     res));
  453         return (0);
  454 }
  455 
  456 static struct resource_list *
  457 sbbc_bus_get_resource_list(device_t dev, device_t child __unused)
  458 {
  459 
  460         return (bus_generic_get_resource_list(dev, dev));
  461 }
  462 
  463 static int
  464 sbbc_bus_setup_intr(device_t dev, device_t child __unused,
  465     struct resource *res, int flags, driver_filter_t *filt,
  466     driver_intr_t *intr, void *arg, void **cookiep)
  467 {
  468 
  469         return (bus_generic_setup_intr(dev, dev, res, flags, filt, intr, arg,
  470             cookiep));
  471 }
  472 
  473 static int
  474 sbbc_bus_teardown_intr(device_t dev, device_t child __unused,
  475     struct resource *res, void *cookie)
  476 {
  477 
  478         return (bus_generic_teardown_intr(dev, dev, res, cookie));
  479 }
  480 
  481 /*
  482  * internal helpers
  483  */
  484 static int
  485 sbbc_parse_toc(bus_space_tag_t bst, bus_space_handle_t bsh)
  486 {
  487         char buf[MAX(SBBC_TAG_KEY_SIZE, SBBC_TOC_MAGIC_SIZE)];
  488         bus_size_t tag;
  489         phandle_t node;
  490         uint32_t off, sram_toc;
  491         u_int i, tags;
  492 
  493         if ((node = OF_finddevice("/chosen")) == -1)
  494                 return (ENXIO);
  495         /* SRAM TOC offset defaults to 0. */
  496         if (OF_getprop(node, "iosram-toc", &sram_toc, sizeof(sram_toc)) <= 0)
  497                 sram_toc = 0;
  498 
  499         bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + sram_toc +
  500             SBBC_TOC_OFF(toc_magic), buf, SBBC_TOC_MAGIC_SIZE);
  501         buf[SBBC_TOC_MAGIC_SIZE - 1] = '\0';
  502         if (strcmp(buf, SBBC_TOC_MAGIC) != 0)
  503                 return (ENXIO);
  504 
  505         tags = SBBC_SRAM_READ_4(sram_toc + SBBC_TOC_OFF(toc_ntags));
  506         for (i = 0; i < tags; i++) {
  507                 tag = sram_toc + SBBC_TOC_OFF(toc_tag) +
  508                     i * sizeof(struct sbbc_sram_tag);
  509                 bus_space_read_region_1(bst, bsh, SBBC_SRAM_OFFSET + tag +
  510                     SBBC_TAG_OFF(tag_key), buf, SBBC_TAG_KEY_SIZE);
  511                 buf[SBBC_TAG_KEY_SIZE - 1] = '\0';
  512                 off = SBBC_SRAM_READ_4(tag + SBBC_TAG_OFF(tag_offset));
  513                 if (strcmp(buf, SBBC_TAG_KEY_SCSOLIE) == 0)
  514                         sbbc_scsolie = off;
  515                 else if (strcmp(buf, SBBC_TAG_KEY_SCSOLIR) == 0)
  516                         sbbc_scsolir = off;
  517                 else if (strcmp(buf, SBBC_TAG_KEY_SOLCONS) == 0)
  518                         sbbc_solcons = off;
  519                 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIE) == 0)
  520                         sbbc_solscie = off;
  521                 else if (strcmp(buf, SBBC_TAG_KEY_SOLSCIR) == 0)
  522                         sbbc_solscir = off;
  523                 else if (strcmp(buf, SBBC_TAG_KEY_TODDATA) == 0)
  524                         sbbc_toddata = off;
  525         }
  526         return (0);
  527 }
  528 
  529 static const char *
  530 sbbc_serengeti_set_console_input(char *new)
  531 {
  532         struct {
  533                 cell_t name;
  534                 cell_t nargs;
  535                 cell_t nreturns;
  536                 cell_t new;
  537                 cell_t old;
  538         } args = {
  539                 (cell_t)SUNW_SETCONSINPUT,
  540                 1,
  541                 1,
  542         };
  543 
  544         args.new = (cell_t)new;
  545         if (ofw_entry(&args) == -1)
  546                 return (NULL);
  547         return ((const char *)args.old);
  548 }
  549 
  550 static inline void
  551 sbbc_send_intr(bus_space_tag_t bst, bus_space_handle_t bsh)
  552 {
  553 
  554         SBBC_EPLD_WRITE_1(SBBC_EPLD_INTERRUPT, SBBC_EPLD_INTERRUPT_ON);
  555         bus_space_barrier(bst, bsh, SBBC_EPLD_OFFSET + SBBC_EPLD_INTERRUPT, 1,
  556             BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
  557 }
  558 
  559 /*
  560  * TOD interface
  561  */
  562 static int
  563 sbbc_tod_gettime(device_t dev, struct timespec *ts)
  564 {
  565         struct sbbc_softc *sc;
  566         bus_space_tag_t bst;
  567         bus_space_handle_t bsh;
  568 
  569         sc = device_get_softc(dev);
  570         bst = rman_get_bustag(sc->sc_res);
  571         bsh = rman_get_bushandle(sc->sc_res);
  572 
  573         ts->tv_sec = SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)) +
  574             SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew));
  575         ts->tv_nsec = 0;
  576         return (0);
  577 }
  578 
  579 static int
  580 sbbc_tod_settime(device_t dev, struct timespec *ts)
  581 {
  582         struct sbbc_softc *sc;
  583         bus_space_tag_t bst;
  584         bus_space_handle_t bsh;
  585 
  586         sc = device_get_softc(dev);
  587         bst = rman_get_bustag(sc->sc_res);
  588         bsh = rman_get_bushandle(sc->sc_res);
  589 
  590         SBBC_SRAM_WRITE_8(sbbc_toddata + SBBC_TOD_OFF(tod_skew), ts->tv_sec -
  591             SBBC_SRAM_READ_8(sbbc_toddata + SBBC_TOD_OFF(tod_time)));
  592         return (0);
  593 }
  594 
  595 /*
  596  * UART bus front-end
  597  */
  598 static device_probe_t sbbc_uart_sbbc_probe;
  599 
  600 static device_method_t sbbc_uart_sbbc_methods[] = {
  601         /* Device interface */
  602         DEVMETHOD(device_probe,         sbbc_uart_sbbc_probe),
  603         DEVMETHOD(device_attach,        uart_bus_attach),
  604         DEVMETHOD(device_detach,        uart_bus_detach),
  605 
  606         DEVMETHOD_END
  607 };
  608 
  609 DEFINE_CLASS_0(uart, sbbc_uart_driver, sbbc_uart_sbbc_methods,
  610     sizeof(struct uart_softc));
  611 DRIVER_MODULE(uart, sbbc, sbbc_uart_driver, uart_devclass, NULL, NULL);
  612 
  613 static int
  614 sbbc_uart_sbbc_probe(device_t dev)
  615 {
  616         struct uart_softc *sc;
  617 
  618         sc = device_get_softc(dev);
  619         sc->sc_class = &uart_sbbc_class;
  620         device_set_desc(dev, "Serengeti console");
  621         return (uart_bus_probe(dev, 0, 0, SBBC_PCI_BAR, 0));
  622 }
  623 
  624 /*
  625  * Low-level UART interface
  626  */
  627 static int sbbc_uart_probe(struct uart_bas *bas);
  628 static void sbbc_uart_init(struct uart_bas *bas, int baudrate, int databits,
  629     int stopbits, int parity);
  630 static void sbbc_uart_term(struct uart_bas *bas);
  631 static void sbbc_uart_putc(struct uart_bas *bas, int c);
  632 static int sbbc_uart_rxready(struct uart_bas *bas);
  633 static int sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx);
  634 
  635 static struct uart_ops sbbc_uart_ops = {
  636         .probe = sbbc_uart_probe,
  637         .init = sbbc_uart_init,
  638         .term = sbbc_uart_term,
  639         .putc = sbbc_uart_putc,
  640         .rxready = sbbc_uart_rxready,
  641         .getc = sbbc_uart_getc,
  642 };
  643 
  644 static int
  645 sbbc_uart_probe(struct uart_bas *bas)
  646 {
  647         bus_space_tag_t bst;
  648         bus_space_handle_t bsh;
  649         int error;
  650 
  651         sbbc_console = 1;
  652         bst = bas->bst;
  653         bsh = bas->bsh;
  654         error = sbbc_parse_toc(bst, bsh);
  655         if (error != 0)
  656                 return (error);
  657 
  658         if (sbbc_scsolie == 0 || sbbc_scsolir == 0 || sbbc_solcons == 0 ||
  659             sbbc_solscie == 0 || sbbc_solscir == 0)
  660                 return (ENXIO);
  661 
  662         if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_magic)) !=
  663             SBBC_CONS_MAGIC || SBBC_SRAM_READ_4(sbbc_solcons +
  664             SBBC_CONS_OFF(cons_version)) < SBBC_CONS_VERSION)
  665                 return (ENXIO);
  666         return (0);
  667 }
  668 
  669 static void
  670 sbbc_uart_init(struct uart_bas *bas, int baudrate __unused,
  671     int databits __unused, int stopbits __unused, int parity __unused)
  672 {
  673         bus_space_tag_t bst;
  674         bus_space_handle_t bsh;
  675 
  676         bst = bas->bst;
  677         bsh = bas->bsh;
  678 
  679         /* Enable output to and space in from the SC interrupts. */
  680         SBBC_SRAM_WRITE_4(sbbc_solscie, SBBC_SRAM_READ_4(sbbc_solscie) |
  681             SBBC_SRAM_CONS_OUT | SBBC_SRAM_CONS_SPACE_IN);
  682         uart_barrier(bas);
  683 
  684         /* Take over the console input. */
  685         sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_CLNT);
  686 }
  687 
  688 static void
  689 sbbc_uart_term(struct uart_bas *bas __unused)
  690 {
  691 
  692         /* Give back the console input. */
  693         sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP);
  694 }
  695 
  696 static void
  697 sbbc_uart_putc(struct uart_bas *bas, int c)
  698 {
  699         bus_space_tag_t bst;
  700         bus_space_handle_t bsh;
  701         uint32_t wrptr;
  702 
  703         bst = bas->bst;
  704         bsh = bas->bsh;
  705 
  706         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
  707             SBBC_CONS_OFF(cons_out_wrptr));
  708         SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, c);
  709         uart_barrier(bas);
  710         if (++wrptr == SBBC_SRAM_READ_4(sbbc_solcons +
  711             SBBC_CONS_OFF(cons_out_end)))
  712                 wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
  713                     SBBC_CONS_OFF(cons_out_begin));
  714         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr),
  715             wrptr);
  716         uart_barrier(bas);
  717 
  718         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
  719             SBBC_SRAM_CONS_OUT);
  720         uart_barrier(bas);
  721         sbbc_send_intr(bst, bsh);
  722 }
  723 
  724 static int
  725 sbbc_uart_rxready(struct uart_bas *bas)
  726 {
  727         bus_space_tag_t bst;
  728         bus_space_handle_t bsh;
  729 
  730         bst = bas->bst;
  731         bsh = bas->bsh;
  732 
  733         if (SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr)) ==
  734             SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr)))
  735                 return (0);
  736         return (1);
  737 }
  738 
  739 static int
  740 sbbc_uart_getc(struct uart_bas *bas, struct mtx *hwmtx)
  741 {
  742         bus_space_tag_t bst;
  743         bus_space_handle_t bsh;
  744         int c;
  745         uint32_t rdptr;
  746 
  747         bst = bas->bst;
  748         bsh = bas->bsh;
  749 
  750         uart_lock(hwmtx);
  751 
  752         while (sbbc_uart_rxready(bas) == 0) {
  753                 uart_unlock(hwmtx);
  754                 DELAY(4);
  755                 uart_lock(hwmtx);
  756         }
  757 
  758         rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr));
  759         c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr);
  760         uart_barrier(bas);
  761         if (++rdptr == SBBC_SRAM_READ_4(sbbc_solcons +
  762             SBBC_CONS_OFF(cons_in_end)))
  763                 rdptr = SBBC_SRAM_READ_4(sbbc_solcons +
  764                     SBBC_CONS_OFF(cons_in_begin));
  765         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr),
  766             rdptr);
  767         uart_barrier(bas);
  768         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
  769             SBBC_SRAM_CONS_SPACE_IN);
  770         uart_barrier(bas);
  771         sbbc_send_intr(bst, bsh);
  772 
  773         uart_unlock(hwmtx);
  774         return (c);
  775 }
  776 
  777 /*
  778  * High-level UART interface
  779  */
  780 static int sbbc_uart_bus_attach(struct uart_softc *sc);
  781 static int sbbc_uart_bus_detach(struct uart_softc *sc);
  782 static int sbbc_uart_bus_flush(struct uart_softc *sc, int what);
  783 static int sbbc_uart_bus_getsig(struct uart_softc *sc);
  784 static int sbbc_uart_bus_ioctl(struct uart_softc *sc, int request,
  785     intptr_t data);
  786 static int sbbc_uart_bus_ipend(struct uart_softc *sc);
  787 static int sbbc_uart_bus_param(struct uart_softc *sc, int baudrate,
  788     int databits, int stopbits, int parity);
  789 static int sbbc_uart_bus_probe(struct uart_softc *sc);
  790 static int sbbc_uart_bus_receive(struct uart_softc *sc);
  791 static int sbbc_uart_bus_setsig(struct uart_softc *sc, int sig);
  792 static int sbbc_uart_bus_transmit(struct uart_softc *sc);
  793 
  794 static kobj_method_t sbbc_uart_methods[] = {
  795         KOBJMETHOD(uart_attach,         sbbc_uart_bus_attach),
  796         KOBJMETHOD(uart_detach,         sbbc_uart_bus_detach),
  797         KOBJMETHOD(uart_flush,          sbbc_uart_bus_flush),
  798         KOBJMETHOD(uart_getsig,         sbbc_uart_bus_getsig),
  799         KOBJMETHOD(uart_ioctl,          sbbc_uart_bus_ioctl),
  800         KOBJMETHOD(uart_ipend,          sbbc_uart_bus_ipend),
  801         KOBJMETHOD(uart_param,          sbbc_uart_bus_param),
  802         KOBJMETHOD(uart_probe,          sbbc_uart_bus_probe),
  803         KOBJMETHOD(uart_receive,        sbbc_uart_bus_receive),
  804         KOBJMETHOD(uart_setsig,         sbbc_uart_bus_setsig),
  805         KOBJMETHOD(uart_transmit,       sbbc_uart_bus_transmit),
  806 
  807         DEVMETHOD_END
  808 };
  809 
  810 struct uart_class uart_sbbc_class = {
  811         "sbbc",
  812         sbbc_uart_methods,
  813         sizeof(struct uart_softc),
  814         .uc_ops = &sbbc_uart_ops,
  815         .uc_range = 1,
  816         .uc_rclk = 0x5bbc       /* arbitrary */
  817 };
  818 
  819 #define SIGCHG(c, i, s, d)                                              \
  820         if ((c) != 0) {                                                 \
  821                 i |= (((i) & (s)) != 0) ? (s) : (s) | (d);              \
  822         } else {                                                        \
  823                 i = (((i) & (s)) != 0) ? ((i) & ~(s)) | (d) : (i);      \
  824         }
  825 
  826 static int
  827 sbbc_uart_bus_attach(struct uart_softc *sc)
  828 {
  829         struct uart_bas *bas;
  830         bus_space_tag_t bst;
  831         bus_space_handle_t bsh;
  832         uint32_t wrptr;
  833 
  834         bas = &sc->sc_bas;
  835         bst = bas->bst;
  836         bsh = bas->bsh;
  837 
  838         sc->sc_rxfifosz = SBBC_SRAM_READ_4(sbbc_solcons +
  839             SBBC_CONS_OFF(cons_in_end)) - SBBC_SRAM_READ_4(sbbc_solcons +
  840             SBBC_CONS_OFF(cons_in_begin)) - 1;
  841         sc->sc_txfifosz = SBBC_SRAM_READ_4(sbbc_solcons +
  842             SBBC_CONS_OFF(cons_out_end)) - SBBC_SRAM_READ_4(sbbc_solcons +
  843             SBBC_CONS_OFF(cons_out_begin)) - 1;
  844 
  845         uart_lock(sc->sc_hwmtx);
  846 
  847         /*
  848          * Let the current output drain before enabling interrupts.  Not
  849          * doing so tends to cause lost output when turning them on.
  850          */
  851         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
  852             SBBC_CONS_OFF(cons_out_wrptr));
  853         while (SBBC_SRAM_READ_4(sbbc_solcons +
  854             SBBC_CONS_OFF(cons_out_rdptr)) != wrptr);
  855                 cpu_spinwait();
  856 
  857         /* Clear and acknowledge possibly outstanding interrupts. */
  858         SBBC_SRAM_WRITE_4(sbbc_scsolir, 0);
  859         uart_barrier(bas);
  860         SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS,
  861             SBBC_SRAM_READ_4(sbbc_scsolir));
  862         uart_barrier(bas);
  863         /* Enable PCI interrupts. */
  864         SBBC_REGS_WRITE_4(SBBC_PCI_INT_ENABLE, SBBC_PCI_ENABLE_INT_A);
  865         uart_barrier(bas);
  866         /* Enable input from and output to SC as well as break interrupts. */
  867         SBBC_SRAM_WRITE_4(sbbc_scsolie, SBBC_SRAM_READ_4(sbbc_scsolie) |
  868             SBBC_SRAM_CONS_IN | SBBC_SRAM_CONS_BRK |
  869             SBBC_SRAM_CONS_SPACE_OUT);
  870         uart_barrier(bas);
  871 
  872         uart_unlock(sc->sc_hwmtx);
  873         return (0);
  874 }
  875 
  876 static int
  877 sbbc_uart_bus_detach(struct uart_softc *sc)
  878 {
  879 
  880         /* Give back the console input. */
  881         sbbc_serengeti_set_console_input(SUNW_SETCONSINPUT_OBP);
  882         return (0);
  883 }
  884 
  885 static int
  886 sbbc_uart_bus_flush(struct uart_softc *sc, int what)
  887 {
  888         struct uart_bas *bas;
  889         bus_space_tag_t bst;
  890         bus_space_handle_t bsh;
  891 
  892         bas = &sc->sc_bas;
  893         bst = bas->bst;
  894         bsh = bas->bsh;
  895 
  896         if ((what & UART_FLUSH_TRANSMITTER) != 0)
  897                 return (ENODEV);
  898         if ((what & UART_FLUSH_RECEIVER) != 0) {
  899                 SBBC_SRAM_WRITE_4(sbbc_solcons +
  900                     SBBC_CONS_OFF(cons_in_rdptr),
  901                     SBBC_SRAM_READ_4(sbbc_solcons +
  902                     SBBC_CONS_OFF(cons_in_wrptr)));
  903                 uart_barrier(bas);
  904         }
  905         return (0);
  906 }
  907 
  908 static int
  909 sbbc_uart_bus_getsig(struct uart_softc *sc)
  910 {
  911         uint32_t dummy, new, old, sig;
  912 
  913         do {
  914                 old = sc->sc_hwsig;
  915                 sig = old;
  916                 dummy = 0;
  917                 SIGCHG(dummy, sig, SER_CTS, SER_DCTS);
  918                 SIGCHG(dummy, sig, SER_DCD, SER_DDCD);
  919                 SIGCHG(dummy, sig, SER_DSR, SER_DDSR);
  920                 new = sig & ~SER_MASK_DELTA;
  921         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
  922         return (sig);
  923 }
  924 
  925 static int
  926 sbbc_uart_bus_ioctl(struct uart_softc *sc, int request, intptr_t data)
  927 {
  928         int error;
  929 
  930         error = 0;
  931         uart_lock(sc->sc_hwmtx);
  932         switch (request) {
  933         case UART_IOCTL_BAUD:
  934                 *(int*)data = 9600;     /* arbitrary */
  935                 break;
  936         default:
  937                 error = EINVAL;
  938                 break;
  939         }
  940         uart_unlock(sc->sc_hwmtx);
  941         return (error);
  942 }
  943 
  944 static int
  945 sbbc_uart_bus_ipend(struct uart_softc *sc)
  946 {
  947         struct uart_bas *bas;
  948         bus_space_tag_t bst;
  949         bus_space_handle_t bsh;
  950         int ipend;
  951         uint32_t reason, status;
  952 
  953         bas = &sc->sc_bas;
  954         bst = bas->bst;
  955         bsh = bas->bsh;
  956 
  957         uart_lock(sc->sc_hwmtx);
  958         status = SBBC_REGS_READ_4(SBBC_PCI_INT_STATUS);
  959         if (status == 0) {
  960                 uart_unlock(sc->sc_hwmtx);
  961                 return (0);
  962         }
  963 
  964         /*
  965          * Unfortunately, we can't use compare and swap for non-cachable
  966          * memory.
  967          */
  968         reason = SBBC_SRAM_READ_4(sbbc_scsolir);
  969         SBBC_SRAM_WRITE_4(sbbc_scsolir, 0);
  970         uart_barrier(bas);
  971         /* Acknowledge the interrupt. */
  972         SBBC_REGS_WRITE_4(SBBC_PCI_INT_STATUS, status);
  973         uart_barrier(bas);
  974 
  975         uart_unlock(sc->sc_hwmtx);
  976 
  977         ipend = 0;
  978         if ((reason & SBBC_SRAM_CONS_IN) != 0)
  979                 ipend |= SER_INT_RXREADY;
  980         if ((reason & SBBC_SRAM_CONS_BRK) != 0)
  981                 ipend |= SER_INT_BREAK;
  982         if ((reason & SBBC_SRAM_CONS_SPACE_OUT) != 0 &&
  983             SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_rdptr)) ==
  984             SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr)))
  985                 ipend |= SER_INT_TXIDLE;
  986         return (ipend);
  987 }
  988 
  989 static int
  990 sbbc_uart_bus_param(struct uart_softc *sc __unused, int baudrate __unused,
  991     int databits __unused, int stopbits __unused, int parity __unused)
  992 {
  993 
  994         return (0);
  995 }
  996 
  997 static int
  998 sbbc_uart_bus_probe(struct uart_softc *sc __unused)
  999 {
 1000 
 1001         if (sbbc_console != 0)
 1002                 return (0);
 1003         return (ENXIO);
 1004 }
 1005 
 1006 static int
 1007 sbbc_uart_bus_receive(struct uart_softc *sc)
 1008 {
 1009         struct uart_bas *bas;
 1010         bus_space_tag_t bst;
 1011         bus_space_handle_t bsh;
 1012         int c;
 1013         uint32_t end, rdptr, wrptr;
 1014 
 1015         bas = &sc->sc_bas;
 1016         bst = bas->bst;
 1017         bsh = bas->bsh;
 1018 
 1019         uart_lock(sc->sc_hwmtx);
 1020 
 1021         end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_end));
 1022         rdptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr));
 1023         wrptr = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_wrptr));
 1024         while (rdptr != wrptr) {
 1025                 if (uart_rx_full(sc) != 0) {
 1026                         sc->sc_rxbuf[sc->sc_rxput] = UART_STAT_OVERRUN;
 1027                         break;
 1028                 }
 1029                 c = SBBC_SRAM_READ_1(sbbc_solcons + rdptr);
 1030                 uart_rx_put(sc, c);
 1031                 if (++rdptr == end)
 1032                         rdptr = SBBC_SRAM_READ_4(sbbc_solcons +
 1033                             SBBC_CONS_OFF(cons_in_begin));
 1034         }
 1035         uart_barrier(bas);
 1036         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_in_rdptr),
 1037             rdptr);
 1038         uart_barrier(bas);
 1039         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
 1040             SBBC_SRAM_CONS_SPACE_IN);
 1041         uart_barrier(bas);
 1042         sbbc_send_intr(bst, bsh);
 1043 
 1044         uart_unlock(sc->sc_hwmtx);
 1045         return (0);
 1046 }
 1047 
 1048 static int
 1049 sbbc_uart_bus_setsig(struct uart_softc *sc, int sig)
 1050 {
 1051         struct uart_bas *bas;
 1052         uint32_t new, old;
 1053 
 1054         bas = &sc->sc_bas;
 1055         do {
 1056                 old = sc->sc_hwsig;
 1057                 new = old;
 1058                 if ((sig & SER_DDTR) != 0) {
 1059                         SIGCHG(sig & SER_DTR, new, SER_DTR, SER_DDTR);
 1060                 }
 1061                 if ((sig & SER_DRTS) != 0) {
 1062                         SIGCHG(sig & SER_RTS, new, SER_RTS, SER_DRTS);
 1063                 }
 1064         } while (!atomic_cmpset_32(&sc->sc_hwsig, old, new));
 1065         return (0);
 1066 }
 1067 
 1068 static int
 1069 sbbc_uart_bus_transmit(struct uart_softc *sc)
 1070 {
 1071         struct uart_bas *bas;
 1072         bus_space_tag_t bst;
 1073         bus_space_handle_t bsh;
 1074         int i;
 1075         uint32_t end, wrptr;
 1076 
 1077         bas = &sc->sc_bas;
 1078         bst = bas->bst;
 1079         bsh = bas->bsh;
 1080 
 1081         uart_lock(sc->sc_hwmtx);
 1082 
 1083         end = SBBC_SRAM_READ_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_end));
 1084         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
 1085             SBBC_CONS_OFF(cons_out_wrptr));
 1086         for (i = 0; i < sc->sc_txdatasz; i++) {
 1087                 SBBC_SRAM_WRITE_1(sbbc_solcons + wrptr, sc->sc_txbuf[i]);
 1088                 if (++wrptr == end)
 1089                         wrptr = SBBC_SRAM_READ_4(sbbc_solcons +
 1090                             SBBC_CONS_OFF(cons_out_begin));
 1091         }
 1092         uart_barrier(bas);
 1093         SBBC_SRAM_WRITE_4(sbbc_solcons + SBBC_CONS_OFF(cons_out_wrptr),
 1094             wrptr);
 1095         uart_barrier(bas);
 1096         SBBC_SRAM_WRITE_4(sbbc_solscir, SBBC_SRAM_READ_4(sbbc_solscir) |
 1097             SBBC_SRAM_CONS_OUT);
 1098         uart_barrier(bas);
 1099         sbbc_send_intr(bst, bsh);
 1100         sc->sc_txbusy = 1;
 1101 
 1102         uart_unlock(sc->sc_hwmtx);
 1103         return (0);
 1104 }

Cache object: 550568dd33ad4b789efd0ea97e7e51d2


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