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

Cache object: 1e2de61e862d32251df83c2fca942413


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