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/sparc64/nexus.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 1998 Massachusetts Institute of Technology
    3  *
    4  * Permission to use, copy, modify, and distribute this software and
    5  * its documentation for any purpose and without fee is hereby
    6  * granted, provided that both the above copyright notice and this
    7  * permission notice appear in all copies, that both the above
    8  * copyright notice and this permission notice appear in all
    9  * supporting documentation, and that the name of M.I.T. not be used
   10  * in advertising or publicity pertaining to distribution of the
   11  * software without specific, written prior permission.  M.I.T. makes
   12  * no representations about the suitability of this software for any
   13  * purpose.  It is provided "as is" without express or implied
   14  * warranty.
   15  * 
   16  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
   17  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
   18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
   19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
   20  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
   22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
   23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
   24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
   26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  */
   29 /*-
   30  * Copyright 2001 by Thomas Moestl <tmm@FreeBSD.org>.  All rights reserved.
   31  *
   32  * Redistribution and use in source and binary forms, with or without
   33  * modification, are permitted provided that the following conditions
   34  * are met:
   35  * 1. Redistributions of source code must retain the above copyright
   36  *    notice, this list of conditions and the following disclaimer.
   37  * 2. Redistributions in binary form must reproduce the above copyright
   38  *    notice, this list of conditions and the following disclaimer in the
   39  *    documentation and/or other materials provided with the distribution.
   40  *
   41  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   42  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   43  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   44  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   45  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   46  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   47  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   48  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   49  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   50  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   51  * SUCH DAMAGE.
   52  *
   53  *      from: FreeBSD: src/sys/i386/i386/nexus.c,v 1.43 2001/02/09
   54  *
   55  * $FreeBSD: releng/5.2/sys/sparc64/sparc64/nexus.c 119291 2003-08-22 07:39:05Z imp $
   56  */
   57 
   58 #include <sys/param.h>
   59 #include <sys/systm.h>
   60 #include <sys/bus.h>
   61 #include <sys/cons.h>
   62 #include <sys/kernel.h>
   63 #include <sys/malloc.h>
   64 
   65 #include <dev/ofw/openfirm.h>
   66 
   67 #include <machine/bus.h>
   68 #include <machine/frame.h>
   69 #include <machine/intr_machdep.h>
   70 #include <machine/nexusvar.h>
   71 #include <machine/ofw_upa.h>
   72 #include <machine/resource.h>
   73 #include <machine/upa.h>
   74 
   75 #include <sys/rman.h>
   76 
   77 /*
   78  * The nexus (which is a pseudo-bus actually) iterates over the nodes that
   79  * hang from the OpenFirmware root node and add them as devices to this bus
   80  * (except some special nodes which are excluded) so that drivers can be
   81  * attached to them. This saves lots of detection work.
   82  * Usually, all devices and bridges that are attached to the UltraSparc UPA
   83  * bus will show up here, plus some pseudo-nodes which are excluded.
   84  * For now, the only node that gets used is probably the pci bus one.
   85  *
   86  * Additionally, interrupt setup/teardown and some resource management are
   87  * done at this level.
   88  *
   89  * Maybe this code should get into dev/ofw to some extent, as some of it should
   90  * work for all OpenFirmware based machines...
   91  */
   92 
   93 static MALLOC_DEFINE(M_NEXUS, "nexus", "nexus device information");
   94 
   95 struct nexus_devinfo {
   96         phandle_t       ndi_node;
   97         /* Some common properties. */
   98         char            *ndi_name;
   99         char            *ndi_device_type;
  100         char            *ndi_model;
  101         struct          upa_regs *ndi_reg;
  102         int             ndi_nreg;
  103         u_int           *ndi_interrupts;
  104         int             ndi_ninterrupts;
  105         bus_space_tag_t ndi_bustag;
  106         bus_dma_tag_t   ndi_dmatag;
  107 };
  108 
  109 struct nexus_softc {
  110         struct rman     sc_intr_rman;
  111         struct rman     sc_mem_rman;
  112 };
  113 
  114 static int nexus_probe(device_t);
  115 static void nexus_probe_nomatch(device_t, device_t);
  116 static int nexus_read_ivar(device_t, device_t, int, uintptr_t *);
  117 static int nexus_write_ivar(device_t, device_t, int, uintptr_t);
  118 static int nexus_setup_intr(device_t, device_t, struct resource *, int,
  119     driver_intr_t *, void *, void **);
  120 static int nexus_teardown_intr(device_t, device_t, struct resource *,
  121     void *);
  122 static struct resource *nexus_alloc_resource(device_t, device_t, int, int *,
  123     u_long, u_long, u_long, u_int);
  124 static int nexus_activate_resource(device_t, device_t, int, int,
  125     struct resource *);
  126 static int nexus_deactivate_resource(device_t, device_t, int, int,
  127     struct resource *);
  128 static int nexus_release_resource(device_t, device_t, int, int,
  129     struct resource *);
  130 
  131 static device_method_t nexus_methods[] = {
  132         /* Device interface */
  133         DEVMETHOD(device_probe,         nexus_probe),
  134         DEVMETHOD(device_attach,        bus_generic_attach),
  135         DEVMETHOD(device_detach,        bus_generic_detach),
  136         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  137         DEVMETHOD(device_suspend,       bus_generic_suspend),
  138         DEVMETHOD(device_resume,        bus_generic_resume),
  139 
  140         /* Bus interface. Resource management is business of the children... */
  141         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  142         DEVMETHOD(bus_probe_nomatch,    nexus_probe_nomatch),
  143         DEVMETHOD(bus_read_ivar,        nexus_read_ivar),
  144         DEVMETHOD(bus_write_ivar,       nexus_write_ivar),
  145         DEVMETHOD(bus_setup_intr,       nexus_setup_intr),
  146         DEVMETHOD(bus_teardown_intr,    nexus_teardown_intr),
  147         DEVMETHOD(bus_alloc_resource,   nexus_alloc_resource),
  148         DEVMETHOD(bus_activate_resource,        nexus_activate_resource),
  149         DEVMETHOD(bus_deactivate_resource,      nexus_deactivate_resource),
  150         DEVMETHOD(bus_release_resource, nexus_release_resource),
  151 
  152         { 0, 0 }
  153 };
  154 
  155 static driver_t nexus_driver = {
  156         "nexus",
  157         nexus_methods,
  158         sizeof(struct nexus_softc),
  159 };
  160 
  161 static devclass_t nexus_devclass;
  162 
  163 DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);
  164 
  165 static char *nexus_excl_name[] = {
  166         "aliases",
  167         "chosen",
  168         "counter-timer",        /* No separate device; handled by psycho/sbus */
  169         "memory",
  170         "openprom",
  171         "options",
  172         "packages",
  173         "virtual-memory",
  174         NULL
  175 };
  176 
  177 static char *nexus_excl_type[] = {
  178         "cpu",
  179         NULL
  180 };
  181 
  182 extern struct bus_space_tag nexus_bustag;
  183 extern struct bus_dma_tag nexus_dmatag;
  184 
  185 static int
  186 nexus_inlist(char *name, char *list[])
  187 {
  188         int i;
  189 
  190         for (i = 0; list[i] != NULL; i++)
  191                 if (strcmp(name, list[i]) == 0)
  192                         return (1);
  193         return (0);
  194 }
  195 
  196 #define NEXUS_EXCLUDED(name, type)                                      \
  197         (nexus_inlist((name), nexus_excl_name) ||                       \
  198         ((type) != NULL && nexus_inlist((type), nexus_excl_type)))
  199 
  200 static int
  201 nexus_probe(device_t dev)
  202 {
  203         phandle_t root;
  204         phandle_t child;
  205         device_t cdev;
  206         struct nexus_devinfo *dinfo;
  207         struct nexus_softc *sc;
  208         char *name, *type;
  209 
  210         if ((root = OF_peer(0)) == -1)
  211                 panic("nexus_probe: OF_peer failed.");
  212 
  213         sc = device_get_softc(dev);
  214         sc->sc_intr_rman.rm_type = RMAN_ARRAY;
  215         sc->sc_intr_rman.rm_descr = "Interrupts";
  216         sc->sc_mem_rman.rm_type = RMAN_ARRAY;
  217         sc->sc_mem_rman.rm_descr = "UPA Device Memory";
  218         if (rman_init(&sc->sc_intr_rman) != 0 ||
  219             rman_init(&sc->sc_mem_rman) != 0 ||
  220             rman_manage_region(&sc->sc_intr_rman, 0, IV_MAX - 1) != 0 ||
  221             rman_manage_region(&sc->sc_mem_rman, UPA_MEMSTART, UPA_MEMEND) != 0)
  222                 panic("nexus_probe: failed to set up rmans");
  223         for (child = OF_child(root); child != 0; child = OF_peer(child)) {
  224                 if (child == -1)
  225                         panic("nexus_probe(): OF_child failed.");
  226                 if (OF_getprop_alloc(child, "name", 1, (void **)&name) == -1)
  227                         continue;
  228                 OF_getprop_alloc(child, "device_type", 1, (void **)&type);
  229                 if (NEXUS_EXCLUDED(name, type)) {
  230                         free(name, M_OFWPROP);
  231                         if (type != NULL)
  232                                 free(type, M_OFWPROP);
  233                         continue;
  234                 }
  235                 cdev = device_add_child(dev, NULL, -1);
  236                 if (cdev != NULL) {
  237                         dinfo = malloc(sizeof(*dinfo), M_NEXUS, M_WAITOK);
  238                         dinfo->ndi_node = child;
  239                         dinfo->ndi_name = name;
  240                         dinfo->ndi_device_type = type;
  241                         OF_getprop_alloc(child, "model", 1,
  242                             (void **)&dinfo->ndi_model);
  243                         dinfo->ndi_nreg = OF_getprop_alloc(child, "reg",
  244                             sizeof(*dinfo->ndi_reg), (void **)&dinfo->ndi_reg);
  245                         dinfo->ndi_ninterrupts = OF_getprop_alloc(child,
  246                             "interrupts", sizeof(*dinfo->ndi_interrupts),
  247                             (void **)&dinfo->ndi_interrupts);
  248                         dinfo->ndi_bustag = &nexus_bustag;
  249                         dinfo->ndi_dmatag = &nexus_dmatag;
  250                         device_set_ivars(cdev, dinfo);
  251                 } else {
  252                         free(name, M_OFWPROP);
  253                         free(type, M_OFWPROP);
  254                 }
  255 
  256         }
  257         device_set_desc(dev, "OpenFirmware Nexus device");
  258         return (0);
  259 }
  260 
  261 static void
  262 nexus_probe_nomatch(device_t dev, device_t child)
  263 {
  264         char *name;
  265         char *type;
  266 
  267         if (BUS_READ_IVAR(dev, child, NEXUS_IVAR_NAME,
  268             (uintptr_t *)&name) != 0 ||
  269             BUS_READ_IVAR(dev, child, NEXUS_IVAR_DEVICE_TYPE,
  270             (uintptr_t *)&type) != 0)
  271                 return;
  272 
  273         if (type == NULL)
  274                 type = "(unknown)";
  275         device_printf(dev, "<%s>, type %s (no driver attached)\n",
  276             name, type);
  277 }
  278 
  279 static int
  280 nexus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
  281 {
  282         struct nexus_devinfo *dinfo;
  283 
  284         if ((dinfo = device_get_ivars(child)) == 0)
  285                 return (ENOENT);
  286         switch (which) {
  287         case NEXUS_IVAR_NODE:
  288                 *result = dinfo->ndi_node;
  289                 break;
  290         case NEXUS_IVAR_NAME:
  291                 *result = (uintptr_t)dinfo->ndi_name;
  292                 break;
  293         case NEXUS_IVAR_DEVICE_TYPE:
  294                 *result = (uintptr_t)dinfo->ndi_device_type;
  295                 break;
  296         case NEXUS_IVAR_MODEL:
  297                 *result = (uintptr_t)dinfo->ndi_model;
  298                 break;
  299         case NEXUS_IVAR_REG:
  300                 *result = (uintptr_t)dinfo->ndi_reg;
  301                 break;
  302         case NEXUS_IVAR_NREG:
  303                 *result = dinfo->ndi_nreg;
  304                 break;
  305         case NEXUS_IVAR_INTERRUPTS:
  306                 *result = (uintptr_t)dinfo->ndi_interrupts;
  307                 break;
  308         case NEXUS_IVAR_NINTERRUPTS:
  309                 *result = dinfo->ndi_ninterrupts;
  310                 break;
  311         case NEXUS_IVAR_DMATAG:
  312                 *result = (uintptr_t)dinfo->ndi_dmatag;
  313                 break;
  314         default:
  315                 return (ENOENT);
  316         }
  317         return 0;
  318 }
  319 
  320 static int
  321 nexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
  322 {
  323         struct nexus_devinfo *dinfo;
  324 
  325         if ((dinfo = device_get_ivars(child)) == 0)
  326                 return (ENOENT);
  327 
  328         switch (which) {
  329         case NEXUS_IVAR_NODE:
  330         case NEXUS_IVAR_NAME:
  331         case NEXUS_IVAR_DEVICE_TYPE:
  332         case NEXUS_IVAR_MODEL:
  333         case NEXUS_IVAR_REG:
  334         case NEXUS_IVAR_NREG:
  335         case NEXUS_IVAR_INTERRUPTS:
  336         case NEXUS_IVAR_NINTERRUPTS:
  337         case NEXUS_IVAR_DMATAG:
  338                 return (EINVAL);
  339         default:
  340                 return (ENOENT);
  341         }
  342         return 0;
  343 }
  344 
  345 static int
  346 nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
  347     driver_intr_t *intr, void *arg, void **cookiep)
  348 {
  349         int error;
  350 
  351         if (res == NULL)
  352                 panic("nexus_setup_intr: NULL interrupt resource!");
  353 
  354         if ((res->r_flags & RF_SHAREABLE) == 0)
  355                 flags |= INTR_EXCL;
  356 
  357         /*
  358          * We depend here on rman_activate_resource() being idempotent.
  359          */
  360         error = rman_activate_resource(res);
  361         if (error)
  362                 return (error);
  363 
  364         error = inthand_add(device_get_nameunit(child), res->r_start,
  365             intr, arg, flags, cookiep);
  366 
  367         return (error);
  368 }
  369 
  370 static int
  371 nexus_teardown_intr(device_t dev, device_t child, struct resource *r, void *ih)
  372 {
  373         inthand_remove(r->r_start, ih);
  374         return (0);
  375 }
  376 
  377 /*
  378  * Allocate resources at the behalf of a child. This only handles interrupts,
  379  * since i/o resources are usually set up by the firmware, and thus need not
  380  * be handled here.
  381  */
  382 static struct resource *
  383 nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
  384     u_long start, u_long end, u_long count, u_int flags)
  385 {
  386         struct  nexus_softc *sc = device_get_softc(bus);
  387         struct  resource *rv;
  388         struct  rman *rm;
  389         int needactivate = flags & RF_ACTIVE;
  390 
  391         flags &= ~RF_ACTIVE;
  392 
  393         switch (type) {
  394         case SYS_RES_IRQ:
  395                 rm = &sc->sc_intr_rman;
  396                 break;
  397         case SYS_RES_MEMORY:
  398                 rm = &sc->sc_mem_rman;
  399                 break;
  400         default:
  401                 return (NULL);
  402         }
  403 
  404         rv = rman_reserve_resource(rm, start, end, count, flags, child);
  405         if (rv == NULL)
  406                 return (NULL);
  407         if (type == SYS_RES_MEMORY) {
  408                 rman_set_bustag(rv, &nexus_bustag);
  409                 rman_set_bushandle(rv, rman_get_start(rv));
  410         }
  411 
  412         if (needactivate) {
  413                 if (bus_activate_resource(child, type, *rid, rv)) {
  414                         rman_release_resource(rv);
  415                         return (NULL);
  416                 }
  417         }
  418 
  419         return (rv);
  420 }
  421 
  422 static int
  423 nexus_activate_resource(device_t bus, device_t child, int type, int rid,
  424     struct resource *r)
  425 {
  426 
  427         /* Not much to be done yet... */
  428         return (rman_activate_resource(r));
  429 }
  430 
  431 static int
  432 nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
  433     struct resource *r)
  434 {
  435 
  436         /* Not much to be done yet... */
  437         return (rman_deactivate_resource(r));
  438 }
  439 
  440 static int
  441 nexus_release_resource(device_t bus, device_t child, int type, int rid,
  442                        struct resource *r)
  443 {
  444         int error;
  445 
  446         if (rman_get_flags(r) & RF_ACTIVE) {
  447                 error = bus_deactivate_resource(child, type, rid, r);
  448                 if (error)
  449                         return error;
  450         }
  451         return (rman_release_resource(r));
  452 }

Cache object: 6b94c8b1123d7296d19941d1f77e4e82


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