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/ofw/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  * SPDX-License-Identifier: BSD-4-Clause
    3  *
    4  * Copyright (C) 1996 Wolfgang Solfrank.
    5  * Copyright (C) 1996 TooLs GmbH.
    6  * All rights reserved.
    7  *
    8  * Redistribution and use in source and binary forms, with or without
    9  * modification, are permitted provided that the following conditions
   10  * are met:
   11  * 1. Redistributions of source code must retain the above copyright
   12  *    notice, this list of conditions and the following disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  * 3. All advertising materials mentioning features or use of this software
   17  *    must display the following acknowledgement:
   18  *      This product includes software developed by TooLs GmbH.
   19  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   20  *    derived from this software without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   23  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   24  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   25  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   26  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   28  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   29  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   30  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   31  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   32  *
   33  * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 #include "opt_platform.h"
   40 #include <sys/param.h>
   41 #include <sys/bus.h>
   42 #include <sys/systm.h>
   43 #include <sys/conf.h>
   44 #include <sys/disk.h>
   45 #include <sys/fcntl.h>
   46 #include <sys/lock.h>
   47 #include <sys/malloc.h>
   48 #include <sys/smp.h>
   49 #include <sys/stat.h>
   50 #include <sys/endian.h>
   51 
   52 #include <net/ethernet.h>
   53 
   54 #include <dev/fdt/fdt_common.h>
   55 #include <dev/ofw/openfirm.h>
   56 #include <dev/ofw/ofw_pci.h>
   57 #include <dev/ofw/ofw_bus.h>
   58 #include <dev/ofw/ofw_subr.h>
   59 
   60 #include <vm/vm.h>
   61 #include <vm/vm_param.h>
   62 #include <vm/vm_page.h>
   63 #include <vm/vm_phys.h>
   64 
   65 #include <machine/bus.h>
   66 #include <machine/cpu.h>
   67 #include <machine/md_var.h>
   68 #include <machine/platform.h>
   69 #include <machine/ofw_machdep.h>
   70 #include <machine/trap.h>
   71 
   72 #include <contrib/libfdt/libfdt.h>
   73 
   74 #ifdef POWERNV
   75 #include <powerpc/powernv/opal.h>
   76 #endif
   77 
   78 static void     *fdt;
   79 int             ofw_real_mode;
   80 
   81 #ifdef AIM
   82 extern register_t ofmsr[5];
   83 extern void     *openfirmware_entry;
   84 char            save_trap_init[0x2f00];          /* EXC_LAST */
   85 char            save_trap_of[0x2f00];            /* EXC_LAST */
   86 
   87 int             ofwcall(void *);
   88 static int      openfirmware(void *args);
   89 
   90 #pragma clang diagnostic push
   91 #pragma clang diagnostic ignored "-Wfortify-source"
   92 
   93 __inline void
   94 ofw_save_trap_vec(char *save_trap_vec)
   95 {
   96         if (!ofw_real_mode || !hw_direct_map)
   97                 return;
   98 
   99         bcopy((void *)PHYS_TO_DMAP(EXC_RST), save_trap_vec, EXC_LAST - EXC_RST);
  100 }
  101 
  102 static __inline void
  103 ofw_restore_trap_vec(char *restore_trap_vec)
  104 {
  105         if (!ofw_real_mode || !hw_direct_map)
  106                 return;
  107 
  108         bcopy(restore_trap_vec, (void *)PHYS_TO_DMAP(EXC_RST),
  109             EXC_LAST - EXC_RST);
  110         __syncicache((void *)PHYS_TO_DMAP(EXC_RSVD), EXC_LAST - EXC_RSVD);
  111 }
  112 
  113 #pragma clang diagnostic pop
  114 
  115 /*
  116  * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
  117  */
  118 register_t      ofw_sprg0_save;
  119 
  120 static __inline void
  121 ofw_sprg_prepare(void)
  122 {
  123         if (ofw_real_mode)
  124                 return;
  125 
  126         /*
  127          * Assume that interrupt are disabled at this point, or
  128          * SPRG1-3 could be trashed
  129          */
  130 #ifdef __powerpc64__
  131         __asm __volatile("mtsprg1 %0\n\t"
  132                          "mtsprg2 %1\n\t"
  133                          "mtsprg3 %2\n\t"
  134                          :
  135                          : "r"(ofmsr[2]),
  136                          "r"(ofmsr[3]),
  137                          "r"(ofmsr[4]));
  138 #else
  139         __asm __volatile("mfsprg0 %0\n\t"
  140                          "mtsprg0 %1\n\t"
  141                          "mtsprg1 %2\n\t"
  142                          "mtsprg2 %3\n\t"
  143                          "mtsprg3 %4\n\t"
  144                          : "=&r"(ofw_sprg0_save)
  145                          : "r"(ofmsr[1]),
  146                          "r"(ofmsr[2]),
  147                          "r"(ofmsr[3]),
  148                          "r"(ofmsr[4]));
  149 #endif
  150 }
  151 
  152 static __inline void
  153 ofw_sprg_restore(void)
  154 {
  155         if (ofw_real_mode)
  156                 return;
  157 
  158         /*
  159          * Note that SPRG1-3 contents are irrelevant. They are scratch
  160          * registers used in the early portion of trap handling when
  161          * interrupts are disabled.
  162          *
  163          * PCPU data cannot be used until this routine is called !
  164          */
  165 #ifndef __powerpc64__
  166         __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
  167 #endif
  168 }
  169 #endif
  170 
  171 static int
  172 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
  173 {
  174         cell_t address_cells, size_cells;
  175         cell_t OFmem[4 * PHYS_AVAIL_SZ];
  176         int sz, i, j;
  177         phandle_t phandle;
  178 
  179         sz = 0;
  180 
  181         /*
  182          * Get #address-cells from root node, defaulting to 1 if it cannot
  183          * be found.
  184          */
  185         phandle = OF_finddevice("/");
  186         if (OF_getencprop(phandle, "#address-cells", &address_cells, 
  187             sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
  188                 address_cells = 1;
  189         if (OF_getencprop(phandle, "#size-cells", &size_cells, 
  190             sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
  191                 size_cells = 1;
  192 
  193         /*
  194          * Get memory.
  195          */
  196         if (node == -1 || (sz = OF_getencprop(node, prop,
  197             OFmem, sizeof(OFmem))) <= 0)
  198                 panic("Physical memory map not found");
  199 
  200         i = 0;
  201         j = 0;
  202         while (i < sz/sizeof(cell_t)) {
  203                 output[j].mr_start = OFmem[i++];
  204                 if (address_cells == 2) {
  205                         output[j].mr_start <<= 32;
  206                         output[j].mr_start += OFmem[i++];
  207                 }
  208                         
  209                 output[j].mr_size = OFmem[i++];
  210                 if (size_cells == 2) {
  211                         output[j].mr_size <<= 32;
  212                         output[j].mr_size += OFmem[i++];
  213                 }
  214 
  215                 if (output[j].mr_start > BUS_SPACE_MAXADDR)
  216                         continue;
  217 
  218                 /*
  219                  * Constrain memory to that which we can access.
  220                  * 32-bit AIM can only reference 32 bits of address currently,
  221                  * but Book-E can access 36 bits.
  222                  */
  223                 if (((uint64_t)output[j].mr_start +
  224                     (uint64_t)output[j].mr_size - 1) >
  225                     BUS_SPACE_MAXADDR) {
  226                         output[j].mr_size = BUS_SPACE_MAXADDR -
  227                             output[j].mr_start + 1;
  228                 }
  229 
  230                 j++;
  231         }
  232 
  233         return (j);
  234 }
  235 
  236 static int
  237 parse_numa_ofw_memory(phandle_t node, const char *prop,
  238     struct numa_mem_region *output)
  239 {
  240         cell_t address_cells, size_cells;
  241         cell_t OFmem[4 * PHYS_AVAIL_SZ];
  242         int sz, i, j;
  243         phandle_t phandle;
  244 
  245         sz = 0;
  246 
  247         /*
  248          * Get #address-cells from root node, defaulting to 1 if it cannot
  249          * be found.
  250          */
  251         phandle = OF_finddevice("/");
  252         if (OF_getencprop(phandle, "#address-cells", &address_cells,
  253             sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
  254                 address_cells = 1;
  255         if (OF_getencprop(phandle, "#size-cells", &size_cells,
  256             sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
  257                 size_cells = 1;
  258 
  259         /*
  260          * Get memory.
  261          */
  262         if (node == -1 || (sz = OF_getencprop(node, prop,
  263             OFmem, sizeof(OFmem))) <= 0)
  264                 panic("Physical memory map not found");
  265 
  266         i = 0;
  267         j = 0;
  268         while (i < sz/sizeof(cell_t)) {
  269                 output[j].mr_start = OFmem[i++];
  270                 if (address_cells == 2) {
  271                         output[j].mr_start <<= 32;
  272                         output[j].mr_start += OFmem[i++];
  273                 }
  274                 output[j].mr_size = OFmem[i++];
  275                 if (size_cells == 2) {
  276                         output[j].mr_size <<= 32;
  277                         output[j].mr_size += OFmem[i++];
  278                 }
  279                 j++;
  280         }
  281 
  282         return (j);
  283 }
  284 
  285 #ifdef FDT
  286 static int
  287 excise_reserved_regions(struct mem_region *avail, int asz,
  288                         struct mem_region *exclude, int esz)
  289 {
  290         int i, j, k;
  291 
  292         for (i = 0; i < asz; i++) {
  293                 for (j = 0; j < esz; j++) {
  294                         /*
  295                          * Case 1: Exclusion region encloses complete
  296                          * available entry. Drop it and move on.
  297                          */
  298                         if (exclude[j].mr_start <= avail[i].mr_start &&
  299                             exclude[j].mr_start + exclude[j].mr_size >=
  300                             avail[i].mr_start + avail[i].mr_size) {
  301                                 for (k = i+1; k < asz; k++)
  302                                         avail[k-1] = avail[k];
  303                                 asz--;
  304                                 i--; /* Repeat some entries */
  305                                 continue;
  306                         }
  307 
  308                         /*
  309                          * Case 2: Exclusion region starts in available entry.
  310                          * Trim it to where the entry begins and append
  311                          * a new available entry with the region after
  312                          * the excluded region, if any.
  313                          */
  314                         if (exclude[j].mr_start >= avail[i].mr_start &&
  315                             exclude[j].mr_start < avail[i].mr_start +
  316                             avail[i].mr_size) {
  317                                 if (exclude[j].mr_start + exclude[j].mr_size <
  318                                     avail[i].mr_start + avail[i].mr_size) {
  319                                         avail[asz].mr_start =
  320                                             exclude[j].mr_start + exclude[j].mr_size;
  321                                         avail[asz].mr_size = avail[i].mr_start +
  322                                              avail[i].mr_size -
  323                                              avail[asz].mr_start;
  324                                         asz++;
  325                                 }
  326 
  327                                 avail[i].mr_size = exclude[j].mr_start -
  328                                     avail[i].mr_start;
  329                         }
  330 
  331                         /*
  332                          * Case 3: Exclusion region ends in available entry.
  333                          * Move start point to where the exclusion zone ends.
  334                          * The case of a contained exclusion zone has already
  335                          * been caught in case 2.
  336                          */
  337                         if (exclude[j].mr_start + exclude[j].mr_size >=
  338                             avail[i].mr_start && exclude[j].mr_start +
  339                             exclude[j].mr_size < avail[i].mr_start +
  340                             avail[i].mr_size) {
  341                                 avail[i].mr_size += avail[i].mr_start;
  342                                 avail[i].mr_start =
  343                                     exclude[j].mr_start + exclude[j].mr_size;
  344                                 avail[i].mr_size -= avail[i].mr_start;
  345                         }
  346                 }
  347         }
  348 
  349         return (asz);
  350 }
  351 
  352 static int
  353 excise_initrd_region(struct mem_region *avail, int asz)
  354 {
  355         phandle_t chosen;
  356         uint64_t start, end;
  357         ssize_t size;
  358         struct mem_region initrdmap[1];
  359         pcell_t cell[2];
  360 
  361         chosen = OF_finddevice("/chosen");
  362 
  363         size = OF_getencprop(chosen, "linux,initrd-start", cell, sizeof(cell));
  364         if (size < 0)
  365                 return (asz);
  366         else if (size == 4)
  367                 start = cell[0];
  368         else if (size == 8)
  369                 start = (uint64_t)cell[0] << 32 | cell[1];
  370         else {
  371                 /* Invalid value length */
  372                 printf("WARNING: linux,initrd-start must be either 4 or 8 bytes long\n");
  373                 return (asz);
  374         }
  375 
  376         size = OF_getencprop(chosen, "linux,initrd-end", cell, sizeof(cell));
  377         if (size < 0)
  378                 return (asz);
  379         else if (size == 4)
  380                 end = cell[0];
  381         else if (size == 8)
  382                 end = (uint64_t)cell[0] << 32 | cell[1];
  383         else {
  384                 /* Invalid value length */
  385                 printf("WARNING: linux,initrd-end must be either 4 or 8 bytes long\n");
  386                 return (asz);
  387         }
  388 
  389         if (end <= start)
  390                 return (asz);
  391 
  392         initrdmap[0].mr_start = start;
  393         initrdmap[0].mr_size = end - start;
  394 
  395         asz = excise_reserved_regions(avail, asz, initrdmap, 1);
  396 
  397         return (asz);
  398 }
  399 
  400 #ifdef POWERNV
  401 static int
  402 excise_msi_region(struct mem_region *avail, int asz)
  403 {
  404         uint64_t start, end;
  405         struct mem_region initrdmap[1];
  406 
  407         /*
  408          * This range of physical addresses is used to implement optimized
  409          * 32 bit MSI interrupts on POWER9. Exclude it to avoid accidentally
  410          * using it for DMA, as this will cause an immediate PHB fence.
  411          * While we could theoretically turn off this behavior in the ETU,
  412          * doing so would break 32-bit MSI, so just reserve the range in 
  413          * the physical map instead.
  414          * See section 4.4.2.8 of the PHB4 specification.
  415          */
  416         start   = 0x00000000ffff0000ul;
  417         end     = 0x00000000fffffffful;
  418 
  419         initrdmap[0].mr_start = start;
  420         initrdmap[0].mr_size = end - start;
  421 
  422         asz = excise_reserved_regions(avail, asz, initrdmap, 1);
  423 
  424         return (asz);
  425 }
  426 #endif
  427 
  428 static int
  429 excise_fdt_reserved(struct mem_region *avail, int asz)
  430 {
  431         struct mem_region fdtmap[32];
  432         ssize_t fdtmapsize;
  433         phandle_t chosen;
  434         int j, fdtentries;
  435 
  436         chosen = OF_finddevice("/chosen");
  437         fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap));
  438 
  439         for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
  440                 fdtmap[j].mr_start = be64toh(fdtmap[j].mr_start) & ~PAGE_MASK;
  441                 fdtmap[j].mr_size = round_page(be64toh(fdtmap[j].mr_size));
  442         }
  443 
  444         KASSERT(j*sizeof(fdtmap[0]) < sizeof(fdtmap),
  445             ("Exceeded number of FDT reservations"));
  446         /* Add a virtual entry for the FDT itself */
  447         if (fdt != NULL) {
  448                 fdtmap[j].mr_start = (vm_offset_t)fdt & ~PAGE_MASK;
  449                 fdtmap[j].mr_size = round_page(fdt_totalsize(fdt));
  450                 fdtmapsize += sizeof(fdtmap[0]);
  451         }
  452 
  453         fdtentries = fdtmapsize/sizeof(fdtmap[0]);
  454         asz = excise_reserved_regions(avail, asz, fdtmap, fdtentries);
  455 
  456         return (asz);
  457 }
  458 #endif
  459 
  460 /*
  461  * This is called during powerpc_init, before the system is really initialized.
  462  * It shall provide the total and the available regions of RAM.
  463  * The available regions need not take the kernel into account.
  464  */
  465 void
  466 ofw_numa_mem_regions(struct numa_mem_region *memp, int *memsz)
  467 {
  468         phandle_t phandle;
  469         int count, msz;
  470         char name[31];
  471         struct numa_mem_region *curmemp;
  472 
  473         msz = 0;
  474         /*
  475          * Get memory from all the /memory nodes.
  476          */
  477         for (phandle = OF_child(OF_peer(0)); phandle != 0;
  478             phandle = OF_peer(phandle)) {
  479                 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
  480                         continue;
  481                 if (strncmp(name, "memory@", strlen("memory@")) != 0)
  482                         continue;
  483 
  484                 count = parse_numa_ofw_memory(phandle, "reg", &memp[msz]);
  485                 if (count == 0)
  486                         continue;
  487                 curmemp = &memp[msz];
  488                 MPASS(count == 1);
  489                 curmemp->mr_domain = platform_node_numa_domain(phandle);
  490                 if (bootverbose)
  491                         printf("%s %#jx-%#jx domain(%ju)\n",
  492                             name, (uintmax_t)curmemp->mr_start,
  493                             (uintmax_t)curmemp->mr_start + curmemp->mr_size,
  494                             (uintmax_t)curmemp->mr_domain);
  495                 msz += count;
  496         }
  497         *memsz = msz;
  498 }
  499 /*
  500  * This is called during powerpc_init, before the system is really initialized.
  501  * It shall provide the total and the available regions of RAM.
  502  * The available regions need not take the kernel into account.
  503  */
  504 void
  505 ofw_mem_regions(struct mem_region *memp, int *memsz,
  506                 struct mem_region *availp, int *availsz)
  507 {
  508         phandle_t phandle;
  509         int asz, msz;
  510         int res;
  511         char name[31];
  512 
  513         asz = msz = 0;
  514 
  515         /*
  516          * Get memory from all the /memory nodes.
  517          */
  518         for (phandle = OF_child(OF_peer(0)); phandle != 0;
  519             phandle = OF_peer(phandle)) {
  520                 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
  521                         continue;
  522                 if (strncmp(name, "memory", sizeof(name)) != 0 &&
  523                     strncmp(name, "memory@", strlen("memory@")) != 0)
  524                         continue;
  525 
  526                 res = parse_ofw_memory(phandle, "reg", &memp[msz]);
  527                 msz += res;
  528 
  529                 /*
  530                  * On POWER9 Systems we might have both linux,usable-memory and
  531                  * reg properties.  'reg' denotes all available memory, but we
  532                  * must use 'linux,usable-memory', a subset, as some memory
  533                  * regions are reserved for NVLink.
  534                  */
  535                 if (OF_getproplen(phandle, "linux,usable-memory") >= 0)
  536                         res = parse_ofw_memory(phandle, "linux,usable-memory",
  537                             &availp[asz]);
  538                 else if (OF_getproplen(phandle, "available") >= 0)
  539                         res = parse_ofw_memory(phandle, "available",
  540                             &availp[asz]);
  541                 else
  542                         res = parse_ofw_memory(phandle, "reg", &availp[asz]);
  543                 asz += res;
  544         }
  545 
  546 #ifdef FDT
  547         phandle = OF_finddevice("/chosen");
  548         if (OF_hasprop(phandle, "fdtmemreserv"))
  549                 asz = excise_fdt_reserved(availp, asz);
  550 
  551         /* If the kernel is being loaded through kexec, initrd region is listed
  552          * in /chosen but the region is not marked as reserved, so, we might exclude
  553          * it here.
  554          */
  555         if (OF_hasprop(phandle, "linux,initrd-start"))
  556                 asz = excise_initrd_region(availp, asz);
  557 #endif
  558 
  559 #ifdef POWERNV
  560         if (opal_check() == 0)
  561                 asz = excise_msi_region(availp, asz);
  562 #endif
  563 
  564         *memsz = msz;
  565         *availsz = asz;
  566 }
  567 
  568 void
  569 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
  570 {
  571 #ifdef AIM
  572         ofmsr[0] = mfmsr();
  573         #ifdef __powerpc64__
  574         ofmsr[0] &= ~PSL_SF;
  575         #ifdef __LITTLE_ENDIAN__
  576         /* Assume OFW is BE. */
  577         ofmsr[0] &= ~PSL_LE;
  578         #endif
  579         #else
  580         __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1]));
  581         #endif
  582         __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2]));
  583         __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3]));
  584         __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4]));
  585         openfirmware_entry = openfirm;
  586 
  587         if (ofmsr[0] & PSL_DR)
  588                 ofw_real_mode = 0;
  589         else
  590                 ofw_real_mode = 1;
  591 
  592         ofw_save_trap_vec(save_trap_init);
  593 #else
  594         ofw_real_mode = 1;
  595 #endif
  596 
  597         fdt = fdt_ptr;
  598 }
  599 
  600 boolean_t
  601 OF_bootstrap()
  602 {
  603         boolean_t status = FALSE;
  604         int err = 0;
  605 
  606 #ifdef AIM
  607         if (openfirmware_entry != NULL) {
  608                 if (ofw_real_mode) {
  609                         status = OF_install(OFW_STD_REAL, 0);
  610                 } else {
  611                         #ifdef __powerpc64__
  612                         status = OF_install(OFW_STD_32BIT, 0);
  613                         #else
  614                         status = OF_install(OFW_STD_DIRECT, 0);
  615                         #endif
  616                 }
  617 
  618                 if (status != TRUE)
  619                         return status;
  620 
  621                 err = OF_init(openfirmware);
  622         } else
  623 #endif
  624         if (fdt != NULL) {
  625 #ifdef FDT
  626 #ifdef AIM
  627                 bus_space_tag_t fdt_bt;
  628                 vm_offset_t tmp_fdt_ptr;
  629                 vm_size_t fdt_size;
  630                 uintptr_t fdt_va;
  631 #endif
  632 
  633                 status = OF_install(OFW_FDT, 0);
  634                 if (status != TRUE)
  635                         return status;
  636 
  637 #ifdef AIM /* AIM-only for now -- Book-E does this remapping in early init */
  638                 /* Get the FDT size for mapping if we can */
  639                 tmp_fdt_ptr = pmap_early_io_map((vm_paddr_t)fdt, PAGE_SIZE);
  640                 if (fdt_check_header((void *)tmp_fdt_ptr) != 0) {
  641                         pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE);
  642                         return FALSE;
  643                 }
  644                 fdt_size = fdt_totalsize((void *)tmp_fdt_ptr);
  645                 pmap_early_io_unmap(tmp_fdt_ptr, PAGE_SIZE);
  646 
  647                 /*
  648                  * Map this for real. Use bus_space_map() to take advantage
  649                  * of its auto-remapping function once the kernel is loaded.
  650                  * This is a dirty hack, but what we have.
  651                  */
  652 #ifdef __LITTLE_ENDIAN__
  653                 fdt_bt = &bs_le_tag;
  654 #else
  655                 fdt_bt = &bs_be_tag;
  656 #endif
  657                 bus_space_map(fdt_bt, (vm_paddr_t)fdt, fdt_size, 0, &fdt_va);
  658                  
  659                 err = OF_init((void *)fdt_va);
  660 #else
  661                 err = OF_init(fdt);
  662 #endif
  663 #endif
  664         } 
  665 
  666         #ifdef FDT_DTB_STATIC
  667         /*
  668          * Check for a statically included blob already in the kernel and
  669          * needing no mapping.
  670          */
  671         else {
  672                 status = OF_install(OFW_FDT, 0);
  673                 if (status != TRUE)
  674                         return status;
  675                 err = OF_init(&fdt_static_dtb);
  676         }
  677         #endif
  678 
  679         if (err != 0) {
  680                 OF_install(NULL, 0);
  681                 status = FALSE;
  682         }
  683 
  684         return (status);
  685 }
  686 
  687 #ifdef AIM
  688 void
  689 ofw_quiesce(void)
  690 {
  691         struct {
  692                 cell_t name;
  693                 cell_t nargs;
  694                 cell_t nreturns;
  695         } args;
  696 
  697         KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
  698 
  699         args.name = (cell_t)(uintptr_t)"quiesce";
  700         args.nargs = 0;
  701         args.nreturns = 0;
  702         openfirmware(&args);
  703 }
  704 
  705 static int
  706 openfirmware_core(void *args)
  707 {
  708         int             result;
  709         register_t      oldmsr;
  710 
  711         if (openfirmware_entry == NULL)
  712                 return (-1);
  713 
  714         /*
  715          * Turn off exceptions - we really don't want to end up
  716          * anywhere unexpected with PCPU set to something strange
  717          * or the stack pointer wrong.
  718          */
  719         oldmsr = intr_disable();
  720 
  721         ofw_sprg_prepare();
  722 
  723         /* Save trap vectors */
  724         ofw_save_trap_vec(save_trap_of);
  725 
  726         /* Restore initially saved trap vectors */
  727         ofw_restore_trap_vec(save_trap_init);
  728 
  729 #ifndef __powerpc64__
  730         /*
  731          * Clear battable[] translations
  732          */
  733         if (!(cpu_features & PPC_FEATURE_64))
  734                 __asm __volatile("mtdbatu 2, %0\n"
  735                                  "mtdbatu 3, %0" : : "r" (0));
  736         isync();
  737 #endif
  738 
  739         result = ofwcall(args);
  740 
  741         /* Restore trap vecotrs */
  742         ofw_restore_trap_vec(save_trap_of);
  743 
  744         ofw_sprg_restore();
  745 
  746         intr_restore(oldmsr);
  747 
  748         return (result);
  749 }
  750 
  751 #ifdef SMP
  752 struct ofw_rv_args {
  753         void *args;
  754         int retval;
  755         volatile int in_progress;
  756 };
  757 
  758 static void
  759 ofw_rendezvous_dispatch(void *xargs)
  760 {
  761         struct ofw_rv_args *rv_args = xargs;
  762 
  763         /* NOTE: Interrupts are disabled here */
  764 
  765         if (PCPU_GET(cpuid) == 0) {
  766                 /*
  767                  * Execute all OF calls on CPU 0
  768                  */
  769                 rv_args->retval = openfirmware_core(rv_args->args);
  770                 rv_args->in_progress = 0;
  771         } else {
  772                 /*
  773                  * Spin with interrupts off on other CPUs while OF has
  774                  * control of the machine.
  775                  */
  776                 while (rv_args->in_progress)
  777                         cpu_spinwait();
  778         }
  779 }
  780 #endif
  781 
  782 static int
  783 openfirmware(void *args)
  784 {
  785         int result;
  786         #ifdef SMP
  787         struct ofw_rv_args rv_args;
  788         #endif
  789 
  790         if (openfirmware_entry == NULL)
  791                 return (-1);
  792 
  793         #ifdef SMP
  794         if (cold) {
  795                 result = openfirmware_core(args);
  796         } else {
  797                 rv_args.args = args;
  798                 rv_args.in_progress = 1;
  799                 smp_rendezvous(smp_no_rendezvous_barrier,
  800                     ofw_rendezvous_dispatch, smp_no_rendezvous_barrier,
  801                     &rv_args);
  802                 result = rv_args.retval;
  803         }
  804         #else
  805         result = openfirmware_core(args);
  806         #endif
  807 
  808         return (result);
  809 }
  810 
  811 void
  812 OF_reboot()
  813 {
  814         struct {
  815                 cell_t name;
  816                 cell_t nargs;
  817                 cell_t nreturns;
  818                 cell_t arg;
  819         } args;
  820 
  821         args.name = (cell_t)(uintptr_t)"interpret";
  822         args.nargs = 1;
  823         args.nreturns = 0;
  824         args.arg = (cell_t)(uintptr_t)"reset-all";
  825         openfirmware_core(&args); /* Don't do rendezvous! */
  826 
  827         for (;;);       /* just in case */
  828 }
  829 
  830 #endif /* AIM */
  831 
  832 void
  833 OF_getetheraddr(device_t dev, u_char *addr)
  834 {
  835         phandle_t       node;
  836 
  837         node = ofw_bus_get_node(dev);
  838         OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
  839 }
  840 
  841 /*
  842  * Return a bus handle and bus tag that corresponds to the register
  843  * numbered regno for the device referenced by the package handle
  844  * dev. This function is intended to be used by console drivers in
  845  * early boot only. It works by mapping the address of the device's
  846  * register in the address space of its parent and recursively walk
  847  * the device tree upward this way.
  848  */
  849 int
  850 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
  851     bus_space_handle_t *handle, bus_size_t *sz)
  852 {
  853         bus_addr_t addr;
  854         bus_size_t size;
  855         pcell_t pci_hi;
  856         int flags, res;
  857 
  858         res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi);
  859         if (res < 0)
  860                 return (res);
  861 
  862         if (pci_hi == OFW_PADDR_NOT_PCI) {
  863                 *tag = &bs_be_tag;
  864                 flags = 0;
  865         } else {
  866                 *tag = &bs_le_tag;
  867                 flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 
  868                     BUS_SPACE_MAP_PREFETCHABLE: 0;
  869         }
  870 
  871         if (sz != NULL)
  872                 *sz = size;
  873 
  874         return (bus_space_map(*tag, addr, size, flags, handle));
  875 }

Cache object: 0103ab5905ea051bbe35e1cc50daad21


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