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/platform.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-2-Clause-FreeBSD
    3  *
    4  * Copyright (c) 2005 Peter Grehan
    5  * Copyright (c) 2009 Nathan Whitehorn
    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  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  */
   30 
   31 #include <sys/cdefs.h>
   32 __FBSDID("$FreeBSD$");
   33 
   34 /*
   35  * Dispatch platform calls to the appropriate platform implementation
   36  * through a previously registered kernel object.
   37  */
   38 
   39 #include <sys/param.h>
   40 #include <sys/kernel.h>
   41 #include <sys/lock.h>
   42 #include <sys/ktr.h>
   43 #include <sys/mutex.h>
   44 #include <sys/proc.h>
   45 #include <sys/systm.h>
   46 #include <sys/smp.h>
   47 #include <sys/sysctl.h>
   48 #include <sys/types.h>
   49 
   50 #include <vm/vm.h>
   51 #include <vm/vm_page.h>
   52 
   53 #include <machine/cpu.h>
   54 #include <machine/md_var.h>
   55 #include <machine/platform.h>
   56 #include <machine/platformvar.h>
   57 #include <machine/smp.h>
   58 
   59 #include "platform_if.h"
   60 
   61 static platform_def_t   *plat_def_impl;
   62 static platform_t       plat_obj;
   63 static struct kobj_ops  plat_kernel_kops;
   64 static struct platform_kobj     plat_kernel_obj;
   65 
   66 static char plat_name[64] = "";
   67 SYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RD | CTLFLAG_TUN,
   68     plat_name, 0, "Platform currently in use");
   69 
   70 static struct mem_region pregions[PHYS_AVAIL_SZ];
   71 static struct mem_region aregions[PHYS_AVAIL_SZ];
   72 static int npregions, naregions;
   73 
   74 /*
   75  * Memory region utilities: determine if two regions overlap,
   76  * and merge two overlapping regions into one
   77  */
   78 static int
   79 memr_overlap(struct mem_region *r1, struct mem_region *r2)
   80 {
   81         if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
   82             (r2->mr_start + r2->mr_size) < r1->mr_start)
   83                 return (FALSE);
   84 
   85         return (TRUE);
   86 }
   87 
   88 static void
   89 memr_merge(struct mem_region *from, struct mem_region *to)
   90 {
   91         vm_offset_t end;
   92         end = uqmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
   93         to->mr_start = uqmin(from->mr_start, to->mr_start);
   94         to->mr_size = end - to->mr_start;
   95 }
   96 
   97 /*
   98  * Quick sort callout for comparing memory regions.
   99  */
  100 static int
  101 mr_cmp(const void *a, const void *b)
  102 {
  103         const struct mem_region *regiona, *regionb;
  104 
  105         regiona = a;
  106         regionb = b;
  107         if (regiona->mr_start < regionb->mr_start)
  108                 return (-1);
  109         else if (regiona->mr_start > regionb->mr_start)
  110                 return (1);
  111         else
  112                 return (0);
  113 }
  114 
  115 void
  116 mem_regions(struct mem_region **phys, int *physsz, struct mem_region **avail,
  117     int *availsz)
  118 {
  119         int i, j, still_merging;
  120 
  121         if (npregions == 0) {
  122                 PLATFORM_MEM_REGIONS(plat_obj, pregions, &npregions,
  123                     aregions, &naregions);
  124                 qsort(pregions, npregions, sizeof(*pregions), mr_cmp);
  125                 qsort(aregions, naregions, sizeof(*aregions), mr_cmp);
  126 
  127                 /* Remove overlapping available regions */
  128                 do {
  129                         still_merging = FALSE;
  130                         for (i = 0; i < naregions; i++) {
  131                                 if (aregions[i].mr_size == 0)
  132                                         continue;
  133                                 for (j = i+1; j < naregions; j++) {
  134                                         if (aregions[j].mr_size == 0)
  135                                                 continue;
  136                                         if (!memr_overlap(&aregions[j],
  137                                             &aregions[i]))
  138                                                 continue;
  139 
  140                                         memr_merge(&aregions[j], &aregions[i]);
  141                                         /* mark inactive */
  142                                         aregions[j].mr_size = 0;
  143                                         still_merging = TRUE;
  144                                 }
  145                         }
  146                 } while (still_merging == TRUE);
  147 
  148                 /* Collapse zero-length available regions */
  149                 for (i = 0; i < naregions; i++) {
  150                         if (aregions[i].mr_size == 0) {
  151                                 memcpy(&aregions[i], &aregions[i+1],
  152                                     (naregions - i - 1)*sizeof(*aregions));
  153                                 naregions--;
  154                                 i--;
  155                         }
  156                 }
  157         }
  158 
  159         if (phys != NULL)
  160                 *phys = pregions;
  161         if (avail != NULL)
  162                 *avail = aregions;
  163         if (physsz != NULL)
  164                 *physsz = npregions;
  165         if (availsz != NULL)
  166                 *availsz = naregions;
  167 }
  168 
  169 int
  170 mem_valid(vm_offset_t addr, int len)
  171 {
  172         int i;
  173 
  174         if (npregions == 0) {
  175                 struct mem_region *p, *a;
  176                 int na, np;
  177                 mem_regions(&p, &np, &a, &na);
  178         }
  179 
  180         for (i = 0; i < npregions; i++)
  181                 if ((addr >= pregions[i].mr_start)
  182                    && (addr + len <= pregions[i].mr_start + pregions[i].mr_size))
  183                         return (0);
  184 
  185         return (EFAULT);
  186 }
  187 
  188 vm_offset_t
  189 platform_real_maxaddr(void)
  190 {
  191         return (PLATFORM_REAL_MAXADDR(plat_obj));
  192 }
  193 
  194 const char *
  195 installed_platform()
  196 {
  197         return (plat_def_impl->name);
  198 }
  199 
  200 u_long
  201 platform_timebase_freq(struct cpuref *cpu)
  202 {
  203         return (PLATFORM_TIMEBASE_FREQ(plat_obj, cpu));
  204 }
  205 
  206 /*
  207  * Put the current CPU, as last step in suspend, to sleep
  208  */
  209 void
  210 platform_sleep()
  211 {
  212         PLATFORM_SLEEP(plat_obj);
  213 }
  214 
  215 int
  216 platform_smp_first_cpu(struct cpuref *cpu)
  217 {
  218         return (PLATFORM_SMP_FIRST_CPU(plat_obj, cpu));
  219 }
  220 
  221 int
  222 platform_smp_next_cpu(struct cpuref *cpu)
  223 {
  224         return (PLATFORM_SMP_NEXT_CPU(plat_obj, cpu));
  225 }
  226 
  227 int
  228 platform_smp_get_bsp(struct cpuref *cpu)
  229 {
  230         return (PLATFORM_SMP_GET_BSP(plat_obj, cpu));
  231 }
  232 
  233 int
  234 platform_smp_start_cpu(struct pcpu *cpu)
  235 {
  236         return (PLATFORM_SMP_START_CPU(plat_obj, cpu));
  237 }
  238 
  239 void
  240 platform_smp_ap_init()
  241 {
  242         PLATFORM_SMP_AP_INIT(plat_obj);
  243 }
  244 
  245 void
  246 platform_smp_probe_threads(void)
  247 {
  248         PLATFORM_SMP_PROBE_THREADS(plat_obj);
  249 }
  250 
  251 #ifdef SMP
  252 struct cpu_group *
  253 cpu_topo(void)
  254 {
  255         return (PLATFORM_SMP_TOPO(plat_obj));
  256 }
  257 #endif
  258 
  259 /*
  260  * Reset back to firmware.
  261  */
  262 void
  263 cpu_reset()
  264 {
  265         PLATFORM_RESET(plat_obj);
  266 }
  267 
  268 void platform_smp_timebase_sync(u_long tb, int ap)
  269 {
  270 
  271         PLATFORM_SMP_TIMEBASE_SYNC(plat_obj, tb, ap);
  272 }
  273 
  274 /*
  275  * Platform install routines. Highest priority wins, using the same
  276  * algorithm as bus attachment.
  277  */
  278 SET_DECLARE(platform_set, platform_def_t);
  279 
  280 void
  281 platform_probe_and_attach()
  282 {
  283         platform_def_t  **platpp, *platp;
  284         int             prio, best_prio;
  285 
  286         plat_obj = &plat_kernel_obj;
  287         best_prio = 0;
  288 
  289         /*
  290          * Try to locate the best platform kobj
  291          */
  292         SET_FOREACH(platpp, platform_set) {
  293                 platp = *platpp;
  294 
  295                 /*
  296                  * Take care of compiling the selected class, and
  297                  * then statically initialise the MMU object
  298                  */
  299                 kobj_class_compile_static(platp, &plat_kernel_kops);
  300                 kobj_init_static((kobj_t)plat_obj, platp);
  301 
  302                 prio = PLATFORM_PROBE(plat_obj);
  303 
  304                 /* Check for errors */
  305                 if (prio > 0)
  306                         continue;
  307 
  308                 /*
  309                  * Check if this module was specifically requested through
  310                  * the loader tunable we provide.
  311                  */
  312                 if (strcmp(platp->name,plat_name) == 0) {
  313                         plat_def_impl = platp;
  314                         break;
  315                 }
  316 
  317                 /* Otherwise, see if it is better than our current best */
  318                 if (plat_def_impl == NULL || prio > best_prio) {
  319                         best_prio = prio;
  320                         plat_def_impl = platp;
  321                 }
  322 
  323                 /*
  324                  * We can't free the KOBJ, since it is static. Reset the ops
  325                  * member of this class so that we can come back later.
  326                  */
  327                 platp->ops = NULL;
  328         }
  329 
  330         if (plat_def_impl == NULL)
  331                 panic("No platform module found!");
  332 
  333         /*
  334          * Recompile to make sure we ended with the
  335          * correct one, and then attach.
  336          */
  337 
  338         kobj_class_compile_static(plat_def_impl, &plat_kernel_kops);
  339         kobj_init_static((kobj_t)plat_obj, plat_def_impl);
  340 
  341         strlcpy(plat_name,plat_def_impl->name,sizeof(plat_name));
  342 
  343         PLATFORM_ATTACH(plat_obj);
  344 }
  345 

Cache object: f12506a28615181cb3f6378dcef21e49


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