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/ofw_bus.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 (C) 1996 Wolfgang Solfrank.
    3  * Copyright (C) 1996 TooLs GmbH.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions and the following disclaimer.
   11  * 2. Redistributions in binary form must reproduce the above copyright
   12  *    notice, this list of conditions and the following disclaimer in the
   13  *    documentation and/or other materials provided with the distribution.
   14  * 3. All advertising materials mentioning features or use of this software
   15  *    must display the following acknowledgement:
   16  *      This product includes software developed by TooLs GmbH.
   17  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   18  *    derived from this software without specific prior written permission.
   19  *
   20  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   23  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   25  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   26  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   27  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   28  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   29  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 /*-
   32  * Copyright (c) 2001 - 2003 by Thomas Moestl <tmm@FreeBSD.org>.
   33  * All rights reserved.
   34  *
   35  * Redistribution and use in source and binary forms, with or without
   36  * modification, are permitted provided that the following conditions
   37  * are met:
   38  * 1. Redistributions of source code must retain the above copyright
   39  *    notice, this list of conditions and the following disclaimer.
   40  * 2. Redistributions in binary form must reproduce the above copyright
   41  *    notice, this list of conditions and the following disclaimer in the
   42  *    documentation and/or other materials provided with the distribution.
   43  *
   44  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   45  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   46  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   47  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
   48  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   49  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   50  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   51  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   52  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
   53  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   54  *
   55  *      from: $NetBSD: ofw_machdep.c,v 1.16 2001/07/20 00:07:14 eeh Exp $
   56  *
   57  * $FreeBSD: releng/5.2/sys/sparc64/sparc64/ofw_bus.c 119338 2003-08-23 00:11:16Z imp $
   58  */
   59 
   60 /*
   61  * OpenFirmware bus support code that is (hopefully) independent from the used
   62  * hardware.
   63  * Maybe this should go into dev/ofw/; there may however be sparc specific
   64  * bits left.
   65  */
   66 
   67 #include "opt_ofw_pci.h"
   68 
   69 #include <sys/param.h>
   70 #include <sys/malloc.h>
   71 #include <sys/systm.h>
   72 
   73 #include <dev/ofw/openfirm.h>
   74 
   75 #include <machine/ofw_bus.h>
   76 
   77 static int
   78 ofw_bus_searchprop(phandle_t node, char *propname, void *buf, int buflen)
   79 {
   80         int rv;
   81 
   82         for (; node != 0; node = OF_parent(node)) {
   83                 if ((rv = OF_getprop(node, propname, buf, buflen)) != -1)
   84                         return (rv);
   85         }
   86         return (-1);
   87 }
   88 
   89 #ifdef OFW_NEWPCI
   90 
   91 void
   92 ofw_bus_setup_iinfo(phandle_t node, struct ofw_bus_iinfo *ii, int intrsz)
   93 {
   94         pcell_t addrc;
   95         int msksz;
   96 
   97         if (OF_getprop(node, "#address-cells", &addrc, sizeof(addrc)) == -1)
   98                 addrc = 2;
   99         ii->opi_addrc = addrc * sizeof(pcell_t);
  100 
  101         ii->opi_imapsz = OF_getprop_alloc(node, "interrupt-map", 1,
  102             (void **)&ii->opi_imap);
  103         if (ii->opi_imapsz > 0) {
  104                 msksz = OF_getprop_alloc(node, "interrupt-map-mask", 1,
  105                     (void **)&ii->opi_imapmsk);
  106                 /*
  107                  * Failure to get the mask is ignored; a full mask is used then.
  108                  * Barf on bad mask sizes, however.
  109                  */
  110                 if (msksz != -1 && msksz != ii->opi_addrc + intrsz) {
  111                         panic("ofw_bus_setup_iinfo: bad interrupt-map-mask "
  112                             "property!");
  113                 }
  114         }
  115 
  116 }
  117 
  118 int
  119 ofw_bus_lookup_imap(phandle_t node, struct ofw_bus_iinfo *ii, void *reg,
  120     int regsz, void *pintr, int pintrsz, void *mintr, int mintrsz,
  121     void *maskbuf)
  122 {
  123         int rv;
  124 
  125         if (ii->opi_imapsz <= 0)
  126                 return (0);
  127         KASSERT(regsz >= ii->opi_addrc,
  128             ("ofw_bus_lookup_imap: register size too small: %d < %d",
  129                 regsz, ii->opi_addrc));
  130         rv = OF_getprop(node, "reg", reg, regsz);
  131         if (rv < regsz)
  132                 panic("ofw_bus_lookup_imap: could not get reg property");
  133         return (ofw_bus_search_intrmap(pintr, pintrsz, reg, ii->opi_addrc,
  134             ii->opi_imap, ii->opi_imapsz, ii->opi_imapmsk, maskbuf, mintr,
  135             mintrsz));
  136 }
  137 
  138 /*
  139  * Map an interrupt using the firmware reg, interrupt-map and
  140  * interrupt-map-mask properties.
  141  * The interrupt property to be mapped must be of size intrsz, and pointed to
  142  * by intr. The regs property of the node for which the mapping is done must
  143  * be passed as regs. This property is an array of register specifications;
  144  * the size of the address part of such a specification must be passed as
  145  * physsz. Only the first element of the property is used.
  146  * imap and imapsz hold the interrupt mask and it's size.
  147  * imapmsk is a pointer to the interrupt-map-mask property, which must have
  148  * a size of physsz + intrsz; it may be NULL, in which case a full mask is
  149  * assumed.
  150  * maskbuf must point to a buffer of length physsz + intrsz.
  151  * The interrupt is returned in result, which must point to a buffer of length
  152  * rintrsz (which gives the expected size of the mapped interrupt).
  153  * Returns 1 if a mapping was found, 0 otherwise.
  154  */
  155 int
  156 ofw_bus_search_intrmap(void *intr, int intrsz, void *regs, int physsz,
  157     void *imap, int imapsz, void *imapmsk, void *maskbuf, void *result,
  158     int rintrsz)
  159 {
  160         phandle_t parent;
  161         u_int8_t *ref = maskbuf;
  162         u_int8_t *uiintr = intr;
  163         u_int8_t *uiregs = regs;
  164         u_int8_t *uiimapmsk = imapmsk;
  165         u_int8_t *mptr;
  166         pcell_t pintrsz;
  167         int i, rsz, tsz;
  168 
  169         rsz = -1;
  170         if (imapmsk != NULL) {
  171                 for (i = 0; i < physsz; i++)
  172                         ref[i] = uiregs[i] & uiimapmsk[i];
  173                 for (i = 0; i < intrsz; i++)
  174                         ref[physsz + i] = uiintr[i] & uiimapmsk[physsz + i];
  175         } else {
  176                 bcopy(regs, ref, physsz);
  177                 bcopy(intr, ref + physsz, intrsz);
  178         }
  179 
  180         mptr = imap;
  181         i = imapsz;
  182         tsz = physsz + intrsz + sizeof(phandle_t) + rintrsz;
  183         while (i > 0) {
  184                 KASSERT(i >= tsz, ("ofw_bus_find_intr: truncated map"));
  185                 bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
  186                 if (ofw_bus_searchprop(parent, "#interrupt-cells",
  187                     &pintrsz, sizeof(pintrsz)) == -1)
  188                         pintrsz = 1;    /* default */
  189                 pintrsz *= sizeof(pcell_t);
  190                 if (pintrsz != rintrsz)
  191                         panic("ofw_bus_search_intrmap: expected interrupt cell "
  192                             "size incorrect: %d != %d", rintrsz, pintrsz);
  193                 if (bcmp(ref, mptr, physsz + intrsz) == 0) {
  194                         bcopy(mptr + physsz + intrsz + sizeof(parent),
  195                             result, rintrsz);
  196                         return (1);
  197                 }
  198                 mptr += tsz;
  199                 i -= tsz;
  200         }
  201         return (0);
  202 }
  203 
  204 #else
  205 /*
  206  * Map an interrupt using the firmware reg, interrupt-map and
  207  * interrupt-map-mask properties.
  208  * The interrupt is returned in *result, which is malloc()'ed. The size of
  209  * the interrupt specifiaction is returned.
  210  */
  211 static int
  212 ofw_bus_find_intr(u_int8_t *intr, int intrsz, u_int8_t *regs, int physsz,
  213     u_int8_t *imap, int imapsz, u_int8_t *imapmsk, u_int8_t **result)
  214 {
  215         phandle_t parent;
  216         char *ref;
  217         u_int8_t *mptr;
  218         pcell_t pintrsz;
  219         int i, rsz, tsz;
  220 
  221         rsz = -1;
  222         ref = malloc(physsz + intrsz, M_TEMP, M_WAITOK);
  223         if (imapmsk != NULL) {
  224                 for (i = 0; i < physsz; i++)
  225                         ref[i] = regs[i] & imapmsk[i];
  226                 for (i = 0; i < intrsz; i++)
  227                         ref[physsz + i] = intr[i] & imapmsk[physsz + i];
  228         } else {
  229                 bcopy(regs, ref, physsz);
  230                 bcopy(intr, ref + physsz, intrsz);
  231         }
  232         mptr = imap;
  233         i = imapsz;
  234         while (i > 0) {
  235                 KASSERT(i >= physsz + sizeof(parent),
  236                     ("ofw_bus_find_intr: truncated map"));
  237                 bcopy(mptr + physsz + intrsz, &parent, sizeof(parent));
  238                 if (ofw_bus_searchprop(parent, "#interrupt-cells",
  239                     &pintrsz, sizeof(pintrsz)) == -1)
  240                         pintrsz = 1;    /* default */
  241                 pintrsz *= sizeof(pcell_t);
  242                 KASSERT(i >= physsz + intrsz + sizeof(parent) +
  243                     pintrsz, ("ofw_bus_find_intr: truncated map"));
  244                 if (bcmp(ref, mptr, physsz + intrsz) == 0) {
  245                         *result = malloc(pintrsz, M_OFWPROP, M_WAITOK);
  246                         bcopy(mptr + physsz + intrsz + sizeof(parent),
  247                             *result, pintrsz);
  248                         rsz = pintrsz;
  249                         break;
  250                 }
  251                 tsz = physsz + intrsz + sizeof(phandle_t) + pintrsz;
  252                 mptr += tsz;
  253                 i -= tsz;
  254         }
  255         free(ref, M_TEMP);
  256         return (rsz);
  257 }
  258 
  259 /*
  260  * Apply the OpenFirmware algorithm for mapping an interrupt. First, the
  261  * 'interrupts' and 'reg' properties are retrieved; those are matched against
  262  * the interrupt map of the next higher node. If there is no match or no such
  263  * propery, we go to the next higher node, using the 'reg' property of the node
  264  * that was just processed unusccessfully.
  265  * When a match occurs, we should continue to search, using the new interrupt
  266  * specification that was just found; this is currently not performed
  267  * (see below).
  268  * When the root node is reached with at least one successful mapping performed,
  269  * and the format is right, the interrupt number is returned.
  270  *
  271  * This should work for all bus systems.
  272  */
  273 u_int32_t
  274 ofw_bus_route_intr(phandle_t node, int intrp, obr_callback_t *cb, void *cookie)
  275 {
  276         u_int8_t *reg, *intr, *tintr, *imap, *imapmsk;
  277         phandle_t parent;
  278         pcell_t addrc, ic;
  279         u_int32_t rv;
  280         int regsz, tisz, isz, imapsz, found;
  281 
  282         found = 0;
  283         reg = imap = imapmsk = NULL;
  284         if (intrp == ORIP_NOINT) {
  285                 isz = OF_getprop_alloc(node, "interrupts", 1, (void **)&intr);
  286                 if (isz < 0)
  287                         return (ORIR_NOTFOUND);
  288         } else {
  289                 ic = intrp;
  290                 isz = sizeof(ic);
  291                 intr = malloc(isz, M_OFWPROP, M_WAITOK);
  292                 bcopy(&ic, intr, isz);
  293         }
  294         /*
  295          * Note that apparently, remapping at multiple levels is allowed;
  296          * however, this causes problems with EBus at least, and seems to never
  297          * be needed, so we disable it for now (*sigh*).
  298          */
  299         for (parent = OF_parent(node); parent != 0 && !found;
  300              parent = OF_parent(node = parent)) {
  301                 if (reg != NULL)
  302                         free(reg, M_OFWPROP);
  303                 regsz = OF_getprop_alloc(node, "reg", 1, (void **)&reg);
  304                 if (regsz < 0)
  305                         panic("ofw_bus_route_intr: could not get reg property");
  306                 imapsz = OF_getprop_alloc(parent, "interrupt-map", 1,
  307                     (void **)&imap);
  308                 if (imapsz == -1) {
  309                         /*
  310                          * Use the callback to allow caller-specific workarounds
  311                          * for firmware bugs (missing properties).
  312                          */
  313                         if (cb != NULL) {
  314                                 tisz = cb(parent, intr, isz, reg, regsz, &tintr,
  315                                     &found, cookie);
  316                                 if (tisz != -1) {
  317                                         isz = tisz;
  318                                         free(intr, M_OFWPROP);
  319                                         intr = tintr;
  320                                 }
  321                         }
  322                         continue;
  323                 }
  324                 if (OF_getprop(parent, "#address-cells", &addrc,
  325                     sizeof(addrc)) == -1)
  326                         addrc = 2;
  327                 addrc *= sizeof(pcell_t);
  328                 /*
  329                  * Failures to get the mask are ignored; a full mask is assumed
  330                  * in this case.
  331                  */
  332                 OF_getprop_alloc(parent, "interrupt-map-mask", 1,
  333                     (void **)&imapmsk);
  334                 tisz = ofw_bus_find_intr(intr, isz, reg, addrc, imap, imapsz,
  335                     imapmsk, &tintr);
  336                 if (tisz != -1) {
  337                         found = 1;
  338                         isz = tisz;
  339                         free(intr, M_OFWPROP);
  340                         intr = tintr;
  341                 }
  342                 free(imap, M_OFWPROP);
  343                 if (imapmsk != NULL)
  344                         free(imapmsk, M_OFWPROP);
  345         }
  346         if (reg != NULL)
  347                 free(reg, M_OFWPROP);
  348 #if 0
  349         /*
  350          * Obviously there are some boxes that don't require mapping at all,
  351          * for example the U30, which has no interrupt maps for children of
  352          * the root PCI bus.
  353          */
  354         if (!found) {
  355                 if (intrp != ORIP_NOINT)
  356                         return (ORIR_NOTFOUND);
  357                 panic("ofw_bus_route_intr: 'interrupts' property, but no "
  358                     "mapping found");
  359         }
  360 #endif
  361         KASSERT(isz == sizeof(u_int32_t),
  362             ("ofw_bus_route_intr: bad interrupt spec size %d", isz));
  363         bcopy(intr, &rv, sizeof(rv));
  364         free(intr, M_OFWPROP);
  365         return (rv);
  366 }
  367 #endif /* OFW_NEWPCI */

Cache object: 1da7a3363cc76ac45aa43c1e59624053


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