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/powerpc/powerpc/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/6.3/sys/powerpc/powerpc/nexus.c 139825 2005-01-07 02:29:27Z imp $
   56  */
   57 #include "opt_psim.h"
   58 
   59 #include <sys/param.h>
   60 #include <sys/systm.h>
   61 #include <sys/module.h>
   62 #include <sys/bus.h>
   63 #include <sys/cons.h>
   64 #include <sys/kernel.h>
   65 #include <sys/malloc.h>
   66 
   67 #include <dev/ofw/openfirm.h>
   68 
   69 #include <machine/bus.h>
   70 #include <machine/frame.h>
   71 #include <machine/intr_machdep.h>
   72 #include <machine/nexusvar.h>
   73 #include <machine/resource.h>
   74 
   75 #include <sys/rman.h>
   76 
   77 #include "pic_if.h"
   78 
   79 /*
   80  * The nexus (which is a pseudo-bus actually) iterates over the nodes that
   81  * exist in Open Firmware and adds them as devices to this bus so that drivers
   82  * can be attached to them.
   83  *
   84  * Maybe this code should get into dev/ofw to some extent, as some of it should
   85  * work for all Open Firmware based machines...
   86  */
   87 
   88 static MALLOC_DEFINE(M_NEXUS, "nexus", "nexus device information");
   89 
   90 struct nexus_devinfo {
   91         phandle_t       ndi_node;
   92         /* Some common properties. */
   93         const char      *ndi_name;
   94         const char      *ndi_device_type;
   95         const char      *ndi_compatible;
   96 };
   97 
   98 struct nexus_softc {
   99         device_t        sc_pic;
  100 };
  101 
  102 /*
  103  * Device interface
  104  */
  105 static int      nexus_probe(device_t);
  106 static void     nexus_probe_nomatch(device_t, device_t);
  107 
  108 /*
  109  * Bus interface
  110  */
  111 static device_t nexus_add_child(device_t, int, const char *, int);
  112 static int      nexus_read_ivar(device_t, device_t, int, uintptr_t *);
  113 static int      nexus_write_ivar(device_t, device_t, int, uintptr_t);
  114 static int      nexus_setup_intr(device_t, device_t, struct resource *, int,
  115                     driver_intr_t *, void *, void **);
  116 static int      nexus_teardown_intr(device_t, device_t, struct resource *,
  117                     void *);
  118 static struct   resource *nexus_alloc_resource(device_t, device_t, int, int *,
  119                     u_long, u_long, u_long, u_int);
  120 static int      nexus_activate_resource(device_t, device_t, int, int,
  121                     struct resource *);
  122 static int      nexus_deactivate_resource(device_t, device_t, int, int,
  123                     struct resource *);
  124 static int      nexus_release_resource(device_t, device_t, int, int,
  125                     struct resource *);
  126 
  127 /*
  128  * Local routines
  129  */
  130 static device_t nexus_device_from_node(device_t, phandle_t);
  131 
  132 static device_method_t nexus_methods[] = {
  133         /* Device interface */
  134         DEVMETHOD(device_probe,         nexus_probe),
  135         DEVMETHOD(device_attach,        bus_generic_attach),
  136         DEVMETHOD(device_detach,        bus_generic_detach),
  137         DEVMETHOD(device_shutdown,      bus_generic_shutdown),
  138         DEVMETHOD(device_suspend,       bus_generic_suspend),
  139         DEVMETHOD(device_resume,        bus_generic_resume),
  140 
  141         /* Bus interface. Resource management is business of the children... */
  142         DEVMETHOD(bus_add_child,        nexus_add_child),
  143         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  144         DEVMETHOD(bus_probe_nomatch,    nexus_probe_nomatch),
  145         DEVMETHOD(bus_read_ivar,        nexus_read_ivar),
  146         DEVMETHOD(bus_write_ivar,       nexus_write_ivar),
  147         DEVMETHOD(bus_setup_intr,       nexus_setup_intr),
  148         DEVMETHOD(bus_teardown_intr,    nexus_teardown_intr),
  149         DEVMETHOD(bus_alloc_resource,   nexus_alloc_resource),
  150         DEVMETHOD(bus_activate_resource,        nexus_activate_resource),
  151         DEVMETHOD(bus_deactivate_resource,      nexus_deactivate_resource),
  152         DEVMETHOD(bus_release_resource, nexus_release_resource),
  153 
  154         { 0, 0 }
  155 };
  156 
  157 static driver_t nexus_driver = {
  158         "nexus",
  159         nexus_methods,
  160         sizeof(struct nexus_softc),
  161 };
  162 
  163 static devclass_t nexus_devclass;
  164 
  165 DRIVER_MODULE(nexus, root, nexus_driver, nexus_devclass, 0, 0);
  166 
  167 static int
  168 nexus_probe(device_t dev)
  169 {
  170         phandle_t       root;
  171         phandle_t       child;
  172         struct          nexus_softc *sc;
  173 
  174         if ((root = OF_peer(0)) == -1)
  175                 panic("nexus_probe: OF_peer failed.");
  176 
  177         sc = device_get_softc(dev);
  178 
  179         /*
  180          * Allow devices to identify
  181          */
  182         bus_generic_probe(dev);
  183 
  184         /*
  185          * Now walk the OFW tree to locate top-level devices
  186          */
  187         for (child = OF_child(root); child != 0; child = OF_peer(child)) {
  188                 if (child == -1)
  189                         panic("nexus_probe(): OF_child failed.");
  190                 (void)nexus_device_from_node(dev, child);
  191 
  192         }
  193         device_set_desc(dev, "Open Firmware Nexus device");
  194         return (0);
  195 }
  196 
  197 static void
  198 nexus_probe_nomatch(device_t dev, device_t child)
  199 {
  200         char    *name, *type;
  201 
  202         if (BUS_READ_IVAR(dev, child, NEXUS_IVAR_NAME,
  203             (uintptr_t *)&name) != 0 ||
  204             BUS_READ_IVAR(dev, child, NEXUS_IVAR_DEVICE_TYPE,
  205             (uintptr_t *)&type) != 0)
  206                 return;
  207 
  208         if (type == NULL)
  209                 type = "(unknown)";
  210 
  211         if (bootverbose)
  212                 device_printf(dev, "<%s>, type %s (no driver attached)\n",
  213                     name, type);
  214 }
  215 
  216 static device_t
  217 nexus_add_child(device_t dev, int order, const char *name, int unit)
  218 {
  219         device_t child;
  220         struct nexus_devinfo *dinfo;
  221 
  222         child = device_add_child_ordered(dev, order, name, unit);
  223         if (child == NULL)
  224                 return (NULL);
  225 
  226         dinfo = malloc(sizeof(struct nexus_devinfo), M_NEXUS, M_NOWAIT|M_ZERO);
  227         if (dinfo == NULL)
  228                 return (NULL);
  229 
  230         dinfo->ndi_node = -1;
  231         dinfo->ndi_name = name;
  232         device_set_ivars(child, dinfo);
  233 
  234         return (child);
  235 }
  236 
  237 
  238 static int
  239 nexus_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
  240 {
  241         struct nexus_devinfo *dinfo;
  242 
  243         if ((dinfo = device_get_ivars(child)) == 0)
  244                 return (ENOENT);
  245         switch (which) {
  246         case NEXUS_IVAR_NODE:
  247                 *result = dinfo->ndi_node;
  248                 break;
  249         case NEXUS_IVAR_NAME:
  250                 *result = (uintptr_t)dinfo->ndi_name;
  251                 break;
  252         case NEXUS_IVAR_DEVICE_TYPE:
  253                 *result = (uintptr_t)dinfo->ndi_device_type;
  254                 break;
  255         case NEXUS_IVAR_COMPATIBLE:
  256                 *result = (uintptr_t)dinfo->ndi_compatible;
  257                 break;
  258         default:
  259                 return (ENOENT);
  260         }
  261         return 0;
  262 }
  263 
  264 static int
  265 nexus_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
  266 {
  267         struct nexus_devinfo *dinfo;
  268 
  269         if ((dinfo = device_get_ivars(child)) == 0)
  270                 return (ENOENT);
  271 
  272         switch (which) {
  273         case NEXUS_IVAR_NAME:
  274                 return (EINVAL);
  275 
  276         /* Identified devices may want to set these */
  277         case NEXUS_IVAR_NODE:
  278                 dinfo->ndi_node = (phandle_t)value;
  279                 break;
  280 
  281         case NEXUS_IVAR_DEVICE_TYPE:
  282                 dinfo->ndi_device_type = (char *)value;
  283                 break;
  284 
  285         default:
  286                 return (ENOENT);
  287         }
  288         return 0;
  289 }
  290 
  291 static int
  292 nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags,
  293     driver_intr_t *intr, void *arg, void **cookiep)
  294 {
  295         struct  nexus_softc *sc;
  296 
  297         sc = device_get_softc(dev);
  298 
  299         if (device_get_state(sc->sc_pic) != DS_ATTACHED)
  300                 panic("nexus_setup_intr: no pic attached\n");
  301 
  302         return (PIC_SETUP_INTR(sc->sc_pic, child, res, flags, intr, arg,
  303             cookiep));
  304 }
  305 
  306 static int
  307 nexus_teardown_intr(device_t dev, device_t child, struct resource *res,
  308     void *ih)
  309 {
  310         struct  nexus_softc *sc;
  311 
  312         sc = device_get_softc(dev);
  313 
  314         if (device_get_state(sc->sc_pic) != DS_ATTACHED)
  315                 panic("nexus_teardown_intr: no pic attached\n");
  316 
  317         return (PIC_TEARDOWN_INTR(sc->sc_pic, child, res, ih));
  318 }
  319 
  320 /*
  321  * Allocate resources at the behest of a child.  This only handles interrupts,
  322  * since I/O resources are handled by child busses.
  323  */
  324 static struct resource *
  325 nexus_alloc_resource(device_t bus, device_t child, int type, int *rid,
  326     u_long start, u_long end, u_long count, u_int flags)
  327 {
  328         struct  nexus_softc *sc;
  329         struct  resource *rv;
  330 
  331         sc = device_get_softc(bus);
  332 
  333         if (type != SYS_RES_IRQ) {
  334                 device_printf(bus, "unknown resource request from %s\n",
  335                     device_get_nameunit(child));
  336                 return (NULL);
  337         }
  338 
  339         if (device_get_state(sc->sc_pic) != DS_ATTACHED)
  340                 panic("nexus_alloc_resource: no pic attached\n");
  341 
  342         rv = PIC_ALLOCATE_INTR(sc->sc_pic, child, rid, start, flags);
  343 
  344         return (rv);
  345 }
  346 
  347 static int
  348 nexus_activate_resource(device_t bus, device_t child, int type, int rid,
  349     struct resource *res)
  350 {
  351 
  352         /* Not much to be done yet... */
  353         return (rman_activate_resource(res));
  354 }
  355 
  356 static int
  357 nexus_deactivate_resource(device_t bus, device_t child, int type, int rid,
  358     struct resource *res)
  359 {
  360 
  361         /* Not much to be done yet... */
  362         return (rman_deactivate_resource(res));
  363 }
  364 
  365 static int
  366 nexus_release_resource(device_t bus, device_t child, int type, int rid,
  367     struct resource *res)
  368 {
  369         struct  nexus_softc *sc;
  370 
  371         sc = device_get_softc(bus);
  372 
  373         if (type != SYS_RES_IRQ) {
  374                 device_printf(bus, "unknown resource request from %s\n",
  375                     device_get_nameunit(child));
  376                 return (EINVAL);
  377         }
  378 
  379         if (device_get_state(sc->sc_pic) != DS_ATTACHED)
  380                 panic("nexus_release_resource: no pic attached\n");
  381 
  382         return (PIC_RELEASE_INTR(sc->sc_pic, child, rid, res));
  383 }
  384 
  385 static device_t
  386 nexus_device_from_node(device_t parent, phandle_t node)
  387 {
  388         device_t        cdev;
  389         struct          nexus_devinfo *dinfo;
  390         char            *name, *type, *compatible;
  391 
  392         OF_getprop_alloc(node, "name", 1, (void **)&name);
  393         OF_getprop_alloc(node, "device_type", 1, (void **)&type);
  394         OF_getprop_alloc(node, "compatible", 1, (void **)&compatible);
  395         cdev = device_add_child(parent, NULL, -1);
  396         if (cdev != NULL) {
  397                 dinfo = malloc(sizeof(*dinfo), M_NEXUS, M_WAITOK);
  398                 dinfo->ndi_node = node;
  399                 dinfo->ndi_name = name;
  400                 dinfo->ndi_device_type = type;
  401                 dinfo->ndi_compatible = compatible;
  402                 device_set_ivars(cdev, dinfo);
  403         } else
  404                 free(name, M_OFWPROP);
  405 
  406         return (cdev);
  407 }
  408 
  409 int
  410 nexus_install_intcntlr(device_t dev)
  411 {
  412         struct  nexus_softc *sc;
  413 
  414         sc = device_get_softc(device_get_parent(dev));
  415         sc->sc_pic = dev;
  416 
  417         return (0);
  418 }

Cache object: ba02936297c8c8beece20ef37deedede


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