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_machdep.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) 2001 by Thomas Moestl <tmm@FreeBSD.org>.
    3  * Copyright (c) 2005 - 2010 by Marius Strobl <marius@FreeBSD.org>.
    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  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
   19  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   20  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   21  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
   22  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
   23  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
   24  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 /*
   31  * Some Open Firmware helper functions that are likely machine dependent.
   32  */
   33 
   34 #include <sys/param.h>
   35 #include <sys/bus.h>
   36 #include <sys/systm.h>
   37 
   38 #include <net/ethernet.h>
   39 
   40 #include <dev/ofw/ofw_bus.h>
   41 #include <dev/ofw/ofw_pci.h>
   42 #include <dev/ofw/openfirm.h>
   43 
   44 #include <machine/bus.h>
   45 #include <machine/idprom.h>
   46 #include <machine/ofw_machdep.h>
   47 #include <machine/stdarg.h>
   48 
   49 void
   50 OF_getetheraddr(device_t dev, u_char *addr)
   51 {
   52         char buf[sizeof("true")];
   53         phandle_t node;
   54         struct idprom idp;
   55 
   56         if ((node = OF_finddevice("/options")) > 0 &&
   57             OF_getprop(node, "local-mac-address?", buf, sizeof(buf)) > 0) {
   58                 buf[sizeof(buf) - 1] = '\0';
   59                 if (strcmp(buf, "true") == 0 &&
   60                     (node = ofw_bus_get_node(dev)) > 0 &&
   61                     OF_getprop(node, "local-mac-address", addr,
   62                     ETHER_ADDR_LEN) == ETHER_ADDR_LEN)
   63                         return;
   64         }
   65 
   66         node = OF_peer(0);
   67         if (node <= 0 || OF_getprop(node, "idprom", &idp, sizeof(idp)) == -1)
   68                 panic("Could not determine the machine Ethernet address");
   69         bcopy(&idp.id_ether, addr, ETHER_ADDR_LEN);
   70 }
   71 
   72 u_int
   73 OF_getscsinitid(device_t dev)
   74 {
   75         phandle_t node;
   76         uint32_t id;
   77 
   78         for (node = ofw_bus_get_node(dev); node != 0; node = OF_parent(node))
   79                 if (OF_getprop(node, "scsi-initiator-id", &id,
   80                     sizeof(id)) > 0)
   81                         return (id);
   82         return (7);
   83 }
   84 
   85 void
   86 OF_panic(const char *fmt, ...)
   87 {
   88         char buf[256];
   89         va_list ap;
   90 
   91         va_start(ap, fmt);
   92         (void)vsnprintf(buf, sizeof(buf), fmt, ap);
   93         OF_printf("OF_panic: %s\n", buf);
   94         va_end(ap);
   95         OF_exit();
   96 }
   97 
   98 static __inline uint32_t
   99 phys_hi_mask_space(const char *bus, uint32_t phys_hi)
  100 {
  101 
  102         if (strcmp(bus, "ebus") == 0 || strcmp(bus, "isa") == 0)
  103                 phys_hi &= 0x1;
  104         else if (strcmp(bus, "pci") == 0)
  105                 phys_hi &= OFW_PCI_PHYS_HI_SPACEMASK;
  106         /* The phys.hi cells of the other busses only contain space bits. */
  107         return (phys_hi);
  108 }
  109 
  110 /*
  111  * Return the physical address and the bus space to use for a node
  112  * referenced by its package handle and the index of the register bank
  113  * to decode.  Intended to be used to together with sparc64_fake_bustag()
  114  * by console drivers in early boot only.
  115  * Works by mapping the address of the node's bank given in the address
  116  * space of its parent upward in the device tree at each bridge along the
  117  * path.
  118  * Currently only really deals with max. 64-bit addresses, i.e. addresses
  119  * consisting of max. 2 phys cells (phys.hi and phys.lo).  If we encounter
  120  * a 3 phys cells address (as with PCI addresses) we assume phys.hi can
  121  * be ignored except for the space bits (generally contained in phys.hi)
  122  * and treat phys.mid as phys.hi.
  123  */
  124 int
  125 OF_decode_addr(phandle_t node, int bank, int *space, bus_addr_t *addr)
  126 {
  127         char name[32];
  128         uint64_t cend, cstart, end, phys, pphys, sz, start;
  129         pcell_t addrc, szc, paddrc;
  130         phandle_t bus, lbus, pbus;
  131         uint32_t banks[10 * 5]; /* 10 PCI banks */
  132         uint32_t cspc, pspc, spc;
  133         int i, j, nbank;
  134 
  135         /*
  136          * In general the addresses are contained in the "reg" property
  137          * of a node.  The first address in the "reg" property of a PCI
  138          * node however is the address of its configuration registers in
  139          * the configuration space of the host bridge.  Additional entries
  140          * denote the memory and I/O addresses.  For relocatable addresses
  141          * the "reg" property contains the BAR, for non-relocatable
  142          * addresses it contains the absolute PCI address.  The PCI-only
  143          * "assigned-addresses" property however always contains the
  144          * absolute PCI addresses.
  145          * The "assigned-addresses" and "reg" properties are arrays of
  146          * address structures consisting of #address-cells 32-bit phys
  147          * cells and #size-cells 32-bit size cells.  If a parent lacks
  148          * the "#address-cells" or "#size-cells" property the default
  149          * for #address-cells to use is 2 and for #size-cells 1.
  150          */
  151         bus = OF_parent(node);
  152         if (bus == 0)
  153                 return (ENXIO);
  154         if (OF_getprop(bus, "name", name, sizeof(name)) == -1)
  155                 return (ENXIO);
  156         name[sizeof(name) - 1] = '\0';
  157         if (OF_getprop(bus, "#address-cells", &addrc, sizeof(addrc)) == -1)
  158                 addrc = 2;
  159         if (OF_getprop(bus, "#size-cells", &szc, sizeof(szc)) == -1)
  160                 szc = 1;
  161         if (addrc < 2 || addrc > 3 || szc < 1 || szc > 2)
  162                 return (ENXIO);
  163         if (strcmp(name, "pci") == 0) {
  164                 if (addrc > 3)
  165                         return (ENXIO);
  166                 nbank = OF_getprop(node, "assigned-addresses", &banks,
  167                     sizeof(banks));
  168         } else {
  169                 if (addrc > 2)
  170                         return (ENXIO);
  171                 nbank = OF_getprop(node, "reg", &banks, sizeof(banks));
  172         }
  173         if (nbank == -1)
  174                 return (ENXIO);
  175         nbank /= sizeof(banks[0]) * (addrc + szc);
  176         if (bank < 0 || bank > nbank - 1)
  177                 return (ENXIO);
  178         bank *= addrc + szc;
  179         spc = phys_hi_mask_space(name, banks[bank]);
  180         /* Skip the high cell for 3-cell addresses. */
  181         bank += addrc - 2;
  182         phys = 0;
  183         for (i = 0; i < MIN(2, addrc); i++)
  184                 phys = ((uint64_t)phys << 32) | banks[bank++];
  185         sz = 0;
  186         for (i = 0; i < szc; i++)
  187                 sz = ((uint64_t)sz << 32) | banks[bank++];
  188         start = phys;
  189         end = phys + sz - 1;
  190 
  191         /*
  192          * Map upward in the device tree at every bridge we encounter
  193          * using their "ranges" properties.
  194          * The "ranges" property of a bridge is an array of a structure
  195          * consisting of that bridge's #address-cells 32-bit child-phys
  196          * cells, its parent bridge #address-cells 32-bit parent-phys
  197          * cells and that bridge's #size-cells 32-bit size cells.
  198          * If a bridge doesn't have a "ranges" property no mapping is
  199          * necessary at that bridge.
  200          */
  201         cspc = 0;
  202         lbus = bus;
  203         while ((pbus = OF_parent(bus)) != 0) {
  204                 if (OF_getprop(pbus, "#address-cells", &paddrc,
  205                     sizeof(paddrc)) == -1)
  206                         paddrc = 2;
  207                 if (paddrc < 2 || paddrc > 3)
  208                         return (ENXIO);
  209                 nbank = OF_getprop(bus, "ranges", &banks, sizeof(banks));
  210                 if (nbank == -1) {
  211                         if (OF_getprop(pbus, "name", name, sizeof(name)) == -1)
  212                                 return (ENXIO);
  213                         name[sizeof(name) - 1] = '\0';
  214                         goto skip;
  215                 }
  216                 if (OF_getprop(bus, "#size-cells", &szc, sizeof(szc)) == -1)
  217                         szc = 1;
  218                 if (szc < 1 || szc > 2)
  219                         return (ENXIO);
  220                 nbank /= sizeof(banks[0]) * (addrc + paddrc + szc);
  221                 bank = 0;
  222                 for (i = 0; i < nbank; i++) {
  223                         cspc = phys_hi_mask_space(name, banks[bank]);
  224                         if (cspc != spc) {
  225                                 bank += addrc + paddrc + szc;
  226                                 continue;
  227                         }
  228                         /* Skip the high cell for 3-cell addresses. */
  229                         bank += addrc - 2;
  230                         phys = 0;
  231                         for (j = 0; j < MIN(2, addrc); j++)
  232                                 phys = ((uint64_t)phys << 32) | banks[bank++];
  233                         pspc = banks[bank];
  234                         /* Skip the high cell for 3-cell addresses. */
  235                         bank += paddrc - 2;
  236                         pphys = 0;
  237                         for (j = 0; j < MIN(2, paddrc); j++)
  238                                 pphys =
  239                                     ((uint64_t)pphys << 32) | banks[bank++];
  240                         sz = 0;
  241                         for (j = 0; j < szc; j++)
  242                                 sz = ((uint64_t)sz << 32) | banks[bank++];
  243                         cstart = phys;
  244                         cend = phys + sz - 1;
  245                         if (start < cstart || start > cend)
  246                                 continue;
  247                         if (end < cstart || end > cend)
  248                                 return (ENXIO);
  249                         if (OF_getprop(pbus, "name", name, sizeof(name)) == -1)
  250                                 return (ENXIO);
  251                         name[sizeof(name) - 1] = '\0';
  252                         spc = phys_hi_mask_space(name, pspc);
  253                         start += pphys - cstart;
  254                         end += pphys - cstart;
  255                         break;
  256                 }
  257                 if (i == nbank)
  258                         return (ENXIO);
  259                 lbus = bus;
  260  skip:
  261                 addrc = paddrc;
  262                 bus = pbus;
  263         }
  264 
  265         *addr = start;
  266         /* Determine the bus space based on the last bus we mapped. */
  267         if (OF_parent(lbus) == 0) {
  268                 *space = NEXUS_BUS_SPACE;
  269                 return (0);
  270         }
  271         if (OF_getprop(lbus, "name", name, sizeof(name)) == -1)
  272                 return (ENXIO);
  273         name[sizeof(name) - 1] = '\0';
  274         if (strcmp(name, "central") == 0 || strcmp(name, "ebus") == 0 ||
  275             strcmp(name, "upa") == 0) {
  276                 *space = NEXUS_BUS_SPACE;
  277                 return (0);
  278         } else if (strcmp(name, "pci") == 0) {
  279                 switch (cspc) {
  280                 case OFW_PCI_PHYS_HI_SPACE_IO:
  281                         *space = PCI_IO_BUS_SPACE;
  282                         return (0);
  283                 case OFW_PCI_PHYS_HI_SPACE_MEM32:
  284                         *space = PCI_MEMORY_BUS_SPACE;
  285                         return (0);
  286                 }
  287         } else if (strcmp(name, "sbus") == 0) {
  288                 *space = SBUS_BUS_SPACE;
  289                 return (0);
  290         }
  291         return (ENXIO);
  292 }

Cache object: 339e1662239663de633fb0b9f0dcef83


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