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  * 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  * $NetBSD: ofw_machdep.c,v 1.5 2000/05/23 13:25:43 tsubai Exp $
   32  */
   33 
   34 #include <sys/cdefs.h>
   35 __FBSDID("$FreeBSD: releng/11.1/sys/powerpc/ofw/ofw_machdep.c 316367 2017-04-01 18:52:48Z jhibbits $");
   36 
   37 #include "opt_platform.h"
   38 #include <sys/param.h>
   39 #include <sys/bus.h>
   40 #include <sys/systm.h>
   41 #include <sys/conf.h>
   42 #include <sys/disk.h>
   43 #include <sys/fcntl.h>
   44 #include <sys/malloc.h>
   45 #include <sys/smp.h>
   46 #include <sys/stat.h>
   47 #include <sys/endian.h>
   48 
   49 #include <net/ethernet.h>
   50 
   51 #include <dev/fdt/fdt_common.h>
   52 #include <dev/ofw/openfirm.h>
   53 #include <dev/ofw/ofw_pci.h>
   54 #include <dev/ofw/ofw_bus.h>
   55 #include <dev/ofw/ofw_subr.h>
   56 
   57 #include <vm/vm.h>
   58 #include <vm/vm_param.h>
   59 #include <vm/vm_page.h>
   60 
   61 #include <machine/bus.h>
   62 #include <machine/cpu.h>
   63 #include <machine/md_var.h>
   64 #include <machine/platform.h>
   65 #include <machine/ofw_machdep.h>
   66 #include <machine/trap.h>
   67 
   68 static void     *fdt;
   69 int             ofw_real_mode;
   70 
   71 #ifdef AIM
   72 extern register_t ofmsr[5];
   73 extern void     *openfirmware_entry;
   74 char            save_trap_init[0x2f00];          /* EXC_LAST */
   75 char            save_trap_of[0x2f00];            /* EXC_LAST */
   76 
   77 int             ofwcall(void *);
   78 static int      openfirmware(void *args);
   79 
   80 __inline void
   81 ofw_save_trap_vec(char *save_trap_vec)
   82 {
   83         if (!ofw_real_mode)
   84                 return;
   85 
   86         bcopy((void *)EXC_RST, save_trap_vec, EXC_LAST - EXC_RST);
   87 }
   88 
   89 static __inline void
   90 ofw_restore_trap_vec(char *restore_trap_vec)
   91 {
   92         if (!ofw_real_mode)
   93                 return;
   94 
   95         bcopy(restore_trap_vec, (void *)EXC_RST, EXC_LAST - EXC_RST);
   96         __syncicache(EXC_RSVD, EXC_LAST - EXC_RSVD);
   97 }
   98 
   99 /*
  100  * Saved SPRG0-3 from OpenFirmware. Will be restored prior to the callback.
  101  */
  102 register_t      ofw_sprg0_save;
  103 
  104 static __inline void
  105 ofw_sprg_prepare(void)
  106 {
  107         if (ofw_real_mode)
  108                 return;
  109         
  110         /*
  111          * Assume that interrupt are disabled at this point, or
  112          * SPRG1-3 could be trashed
  113          */
  114 #ifdef __powerpc64__
  115         __asm __volatile("mtsprg1 %0\n\t"
  116                          "mtsprg2 %1\n\t"
  117                          "mtsprg3 %2\n\t"
  118                          :
  119                          : "r"(ofmsr[2]),
  120                          "r"(ofmsr[3]),
  121                          "r"(ofmsr[4]));
  122 #else
  123         __asm __volatile("mfsprg0 %0\n\t"
  124                          "mtsprg0 %1\n\t"
  125                          "mtsprg1 %2\n\t"
  126                          "mtsprg2 %3\n\t"
  127                          "mtsprg3 %4\n\t"
  128                          : "=&r"(ofw_sprg0_save)
  129                          : "r"(ofmsr[1]),
  130                          "r"(ofmsr[2]),
  131                          "r"(ofmsr[3]),
  132                          "r"(ofmsr[4]));
  133 #endif
  134 }
  135 
  136 static __inline void
  137 ofw_sprg_restore(void)
  138 {
  139         if (ofw_real_mode)
  140                 return;
  141         
  142         /*
  143          * Note that SPRG1-3 contents are irrelevant. They are scratch
  144          * registers used in the early portion of trap handling when
  145          * interrupts are disabled.
  146          *
  147          * PCPU data cannot be used until this routine is called !
  148          */
  149 #ifndef __powerpc64__
  150         __asm __volatile("mtsprg0 %0" :: "r"(ofw_sprg0_save));
  151 #endif
  152 }
  153 #endif
  154 
  155 static int
  156 parse_ofw_memory(phandle_t node, const char *prop, struct mem_region *output)
  157 {
  158         cell_t address_cells, size_cells;
  159         cell_t OFmem[4 * PHYS_AVAIL_SZ];
  160         int sz, i, j;
  161         phandle_t phandle;
  162 
  163         sz = 0;
  164 
  165         /*
  166          * Get #address-cells from root node, defaulting to 1 if it cannot
  167          * be found.
  168          */
  169         phandle = OF_finddevice("/");
  170         if (OF_getencprop(phandle, "#address-cells", &address_cells, 
  171             sizeof(address_cells)) < (ssize_t)sizeof(address_cells))
  172                 address_cells = 1;
  173         if (OF_getencprop(phandle, "#size-cells", &size_cells, 
  174             sizeof(size_cells)) < (ssize_t)sizeof(size_cells))
  175                 size_cells = 1;
  176 
  177         /*
  178          * Get memory.
  179          */
  180         if (node == -1 || (sz = OF_getencprop(node, prop,
  181             OFmem, sizeof(OFmem))) <= 0)
  182                 panic("Physical memory map not found");
  183 
  184         i = 0;
  185         j = 0;
  186         while (i < sz/sizeof(cell_t)) {
  187               #if !defined(__powerpc64__) && !defined(BOOKE)
  188                 /* On 32-bit PPC (OEA), ignore regions starting above 4 GB */
  189                 if (address_cells > 1 && OFmem[i] > 0) {
  190                         i += address_cells + size_cells;
  191                         continue;
  192                 }
  193               #endif
  194 
  195                 output[j].mr_start = OFmem[i++];
  196                 if (address_cells == 2) {
  197                         output[j].mr_start <<= 32;
  198                         output[j].mr_start += OFmem[i++];
  199                 }
  200                         
  201                 output[j].mr_size = OFmem[i++];
  202                 if (size_cells == 2) {
  203                         output[j].mr_size <<= 32;
  204                         output[j].mr_size += OFmem[i++];
  205                 }
  206 
  207               #if !defined(__powerpc64__) && !defined(BOOKE)
  208                 /* Book-E can support 36-bit addresses. */
  209                 /*
  210                  * Check for memory regions extending above 32-bit
  211                  * memory space, and restrict them to stay there.
  212                  */
  213                 if (((uint64_t)output[j].mr_start +
  214                     (uint64_t)output[j].mr_size) >
  215                     BUS_SPACE_MAXADDR_32BIT) {
  216                         output[j].mr_size = BUS_SPACE_MAXADDR_32BIT -
  217                             output[j].mr_start;
  218                 }
  219               #endif
  220 
  221                 j++;
  222         }
  223         sz = j*sizeof(output[0]);
  224 
  225         return (sz);
  226 }
  227 
  228 static int
  229 excise_fdt_reserved(struct mem_region *avail, int asz)
  230 {
  231         struct {
  232                 uint64_t address;
  233                 uint64_t size;
  234         } fdtmap[16];
  235         ssize_t fdtmapsize;
  236         phandle_t chosen;
  237         int i, j, k;
  238 
  239         chosen = OF_finddevice("/chosen");
  240         fdtmapsize = OF_getprop(chosen, "fdtmemreserv", fdtmap, sizeof(fdtmap));
  241 
  242         for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
  243                 fdtmap[j].address = be64toh(fdtmap[j].address);
  244                 fdtmap[j].size = be64toh(fdtmap[j].size);
  245         }
  246 
  247         for (i = 0; i < asz; i++) {
  248                 for (j = 0; j < fdtmapsize/sizeof(fdtmap[0]); j++) {
  249                         /*
  250                          * Case 1: Exclusion region encloses complete
  251                          * available entry. Drop it and move on.
  252                          */
  253                         if (fdtmap[j].address <= avail[i].mr_start &&
  254                             fdtmap[j].address + fdtmap[j].size >=
  255                             avail[i].mr_start + avail[i].mr_size) {
  256                                 for (k = i+1; k < asz; k++)
  257                                         avail[k-1] = avail[k];
  258                                 asz--;
  259                                 i--; /* Repeat some entries */
  260                                 continue;
  261                         }
  262 
  263                         /*
  264                          * Case 2: Exclusion region starts in available entry.
  265                          * Trim it to where the entry begins and append
  266                          * a new available entry with the region after
  267                          * the excluded region, if any.
  268                          */
  269                         if (fdtmap[j].address >= avail[i].mr_start &&
  270                             fdtmap[j].address < avail[i].mr_start +
  271                             avail[i].mr_size) {
  272                                 if (fdtmap[j].address + fdtmap[j].size < 
  273                                     avail[i].mr_start + avail[i].mr_size) {
  274                                         avail[asz].mr_start =
  275                                             fdtmap[j].address + fdtmap[j].size;
  276                                         avail[asz].mr_size = avail[i].mr_start +
  277                                              avail[i].mr_size -
  278                                              avail[asz].mr_start;
  279                                         asz++;
  280                                 }
  281 
  282                                 avail[i].mr_size = fdtmap[j].address -
  283                                     avail[i].mr_start;
  284                         }
  285 
  286                         /*
  287                          * Case 3: Exclusion region ends in available entry.
  288                          * Move start point to where the exclusion zone ends.
  289                          * The case of a contained exclusion zone has already
  290                          * been caught in case 2.
  291                          */
  292                         if (fdtmap[j].address + fdtmap[j].size >=
  293                             avail[i].mr_start && fdtmap[j].address +
  294                             fdtmap[j].size < avail[i].mr_start +
  295                             avail[i].mr_size) {
  296                                 avail[i].mr_size += avail[i].mr_start;
  297                                 avail[i].mr_start =
  298                                     fdtmap[j].address + fdtmap[j].size;
  299                                 avail[i].mr_size -= avail[i].mr_start;
  300                         }
  301                 }
  302         }
  303 
  304         return (asz);
  305 }
  306 
  307 /*
  308  * This is called during powerpc_init, before the system is really initialized.
  309  * It shall provide the total and the available regions of RAM.
  310  * The available regions need not take the kernel into account.
  311  */
  312 void
  313 ofw_mem_regions(struct mem_region *memp, int *memsz,
  314                 struct mem_region *availp, int *availsz)
  315 {
  316         phandle_t phandle;
  317         int asz, msz;
  318         int res;
  319         char name[31];
  320 
  321         asz = msz = 0;
  322 
  323         /*
  324          * Get memory from all the /memory nodes.
  325          */
  326         for (phandle = OF_child(OF_peer(0)); phandle != 0;
  327             phandle = OF_peer(phandle)) {
  328                 if (OF_getprop(phandle, "name", name, sizeof(name)) <= 0)
  329                         continue;
  330                 if (strncmp(name, "memory", sizeof(name)) != 0 &&
  331                     strncmp(name, "memory@", strlen("memory@")) != 0)
  332                         continue;
  333 
  334                 res = parse_ofw_memory(phandle, "reg", &memp[msz]);
  335                 msz += res/sizeof(struct mem_region);
  336                 if (OF_getproplen(phandle, "available") >= 0)
  337                         res = parse_ofw_memory(phandle, "available",
  338                             &availp[asz]);
  339                 else
  340                         res = parse_ofw_memory(phandle, "reg", &availp[asz]);
  341                 asz += res/sizeof(struct mem_region);
  342         }
  343 
  344         phandle = OF_finddevice("/chosen");
  345         if (OF_hasprop(phandle, "fdtmemreserv"))
  346                 asz = excise_fdt_reserved(availp, asz);
  347 
  348         *memsz = msz;
  349         *availsz = asz;
  350 }
  351 
  352 void
  353 OF_initial_setup(void *fdt_ptr, void *junk, int (*openfirm)(void *))
  354 {
  355 #ifdef AIM
  356         ofmsr[0] = mfmsr();
  357         #ifdef __powerpc64__
  358         ofmsr[0] &= ~PSL_SF;
  359         #else
  360         __asm __volatile("mfsprg0 %0" : "=&r"(ofmsr[1]));
  361         #endif
  362         __asm __volatile("mfsprg1 %0" : "=&r"(ofmsr[2]));
  363         __asm __volatile("mfsprg2 %0" : "=&r"(ofmsr[3]));
  364         __asm __volatile("mfsprg3 %0" : "=&r"(ofmsr[4]));
  365         openfirmware_entry = openfirm;
  366 
  367         if (ofmsr[0] & PSL_DR)
  368                 ofw_real_mode = 0;
  369         else
  370                 ofw_real_mode = 1;
  371 
  372         ofw_save_trap_vec(save_trap_init);
  373 #else
  374         ofw_real_mode = 1;
  375 #endif
  376 
  377         fdt = fdt_ptr;
  378 
  379         #ifdef FDT_DTB_STATIC
  380         /* Check for a statically included blob */
  381         if (fdt == NULL)
  382                 fdt = &fdt_static_dtb;
  383         #endif
  384 }
  385 
  386 boolean_t
  387 OF_bootstrap()
  388 {
  389         boolean_t status = FALSE;
  390 
  391 #ifdef AIM
  392         if (openfirmware_entry != NULL) {
  393                 if (ofw_real_mode) {
  394                         status = OF_install(OFW_STD_REAL, 0);
  395                 } else {
  396                         #ifdef __powerpc64__
  397                         status = OF_install(OFW_STD_32BIT, 0);
  398                         #else
  399                         status = OF_install(OFW_STD_DIRECT, 0);
  400                         #endif
  401                 }
  402 
  403                 if (status != TRUE)
  404                         return status;
  405 
  406                 OF_init(openfirmware);
  407         } else
  408 #endif
  409         if (fdt != NULL) {
  410                 status = OF_install(OFW_FDT, 0);
  411 
  412                 if (status != TRUE)
  413                         return status;
  414 
  415                 OF_init(fdt);
  416                 OF_interpret("perform-fixup", 0);
  417         } 
  418 
  419         return (status);
  420 }
  421 
  422 #ifdef AIM
  423 void
  424 ofw_quiesce(void)
  425 {
  426         struct {
  427                 cell_t name;
  428                 cell_t nargs;
  429                 cell_t nreturns;
  430         } args;
  431 
  432         KASSERT(!pmap_bootstrapped, ("Cannot call ofw_quiesce after VM is up"));
  433 
  434         args.name = (cell_t)(uintptr_t)"quiesce";
  435         args.nargs = 0;
  436         args.nreturns = 0;
  437         openfirmware(&args);
  438 }
  439 
  440 static int
  441 openfirmware_core(void *args)
  442 {
  443         int             result;
  444         register_t      oldmsr;
  445 
  446         if (openfirmware_entry == NULL)
  447                 return (-1);
  448 
  449         /*
  450          * Turn off exceptions - we really don't want to end up
  451          * anywhere unexpected with PCPU set to something strange
  452          * or the stack pointer wrong.
  453          */
  454         oldmsr = intr_disable();
  455 
  456         ofw_sprg_prepare();
  457 
  458         /* Save trap vectors */
  459         ofw_save_trap_vec(save_trap_of);
  460 
  461         /* Restore initially saved trap vectors */
  462         ofw_restore_trap_vec(save_trap_init);
  463 
  464 #if defined(AIM) && !defined(__powerpc64__)
  465         /*
  466          * Clear battable[] translations
  467          */
  468         if (!(cpu_features & PPC_FEATURE_64))
  469                 __asm __volatile("mtdbatu 2, %0\n"
  470                                  "mtdbatu 3, %0" : : "r" (0));
  471         isync();
  472 #endif
  473 
  474         result = ofwcall(args);
  475 
  476         /* Restore trap vecotrs */
  477         ofw_restore_trap_vec(save_trap_of);
  478 
  479         ofw_sprg_restore();
  480 
  481         intr_restore(oldmsr);
  482 
  483         return (result);
  484 }
  485 
  486 #ifdef SMP
  487 struct ofw_rv_args {
  488         void *args;
  489         int retval;
  490         volatile int in_progress;
  491 };
  492 
  493 static void
  494 ofw_rendezvous_dispatch(void *xargs)
  495 {
  496         struct ofw_rv_args *rv_args = xargs;
  497 
  498         /* NOTE: Interrupts are disabled here */
  499 
  500         if (PCPU_GET(cpuid) == 0) {
  501                 /*
  502                  * Execute all OF calls on CPU 0
  503                  */
  504                 rv_args->retval = openfirmware_core(rv_args->args);
  505                 rv_args->in_progress = 0;
  506         } else {
  507                 /*
  508                  * Spin with interrupts off on other CPUs while OF has
  509                  * control of the machine.
  510                  */
  511                 while (rv_args->in_progress)
  512                         cpu_spinwait();
  513         }
  514 }
  515 #endif
  516 
  517 static int
  518 openfirmware(void *args)
  519 {
  520         int result;
  521         #ifdef SMP
  522         struct ofw_rv_args rv_args;
  523         #endif
  524 
  525         if (openfirmware_entry == NULL)
  526                 return (-1);
  527 
  528         #ifdef SMP
  529         rv_args.args = args;
  530         rv_args.in_progress = 1;
  531         smp_rendezvous(smp_no_rendevous_barrier, ofw_rendezvous_dispatch,
  532             smp_no_rendevous_barrier, &rv_args);
  533         result = rv_args.retval;
  534         #else
  535         result = openfirmware_core(args);
  536         #endif
  537 
  538         return (result);
  539 }
  540 
  541 void
  542 OF_reboot()
  543 {
  544         struct {
  545                 cell_t name;
  546                 cell_t nargs;
  547                 cell_t nreturns;
  548                 cell_t arg;
  549         } args;
  550 
  551         args.name = (cell_t)(uintptr_t)"interpret";
  552         args.nargs = 1;
  553         args.nreturns = 0;
  554         args.arg = (cell_t)(uintptr_t)"reset-all";
  555         openfirmware_core(&args); /* Don't do rendezvous! */
  556 
  557         for (;;);       /* just in case */
  558 }
  559 
  560 #endif /* AIM */
  561 
  562 void
  563 OF_getetheraddr(device_t dev, u_char *addr)
  564 {
  565         phandle_t       node;
  566 
  567         node = ofw_bus_get_node(dev);
  568         OF_getprop(node, "local-mac-address", addr, ETHER_ADDR_LEN);
  569 }
  570 
  571 /*
  572  * Return a bus handle and bus tag that corresponds to the register
  573  * numbered regno for the device referenced by the package handle
  574  * dev. This function is intended to be used by console drivers in
  575  * early boot only. It works by mapping the address of the device's
  576  * register in the address space of its parent and recursively walk
  577  * the device tree upward this way.
  578  */
  579 int
  580 OF_decode_addr(phandle_t dev, int regno, bus_space_tag_t *tag,
  581     bus_space_handle_t *handle, bus_size_t *sz)
  582 {
  583         bus_addr_t addr;
  584         bus_size_t size;
  585         pcell_t pci_hi;
  586         int flags, res;
  587 
  588         res = ofw_reg_to_paddr(dev, regno, &addr, &size, &pci_hi);
  589         if (res < 0)
  590                 return (res);
  591 
  592         if (pci_hi == OFW_PADDR_NOT_PCI) {
  593                 *tag = &bs_be_tag;
  594                 flags = 0;
  595         } else {
  596                 *tag = &bs_le_tag;
  597                 flags = (pci_hi & OFW_PCI_PHYS_HI_PREFETCHABLE) ? 
  598                     BUS_SPACE_MAP_PREFETCHABLE: 0;
  599         }
  600 
  601         if (sz != NULL)
  602                 *sz = size;
  603 
  604         return (bus_space_map(*tag, addr, size, flags, handle));
  605 }
  606 

Cache object: a9e969496893d96818921dbf8f745839


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