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_param.h>
   52 #include <vm/vm_page.h>
   53 #include <vm/vm_phys.h>
   54 
   55 #include <machine/cpu.h>
   56 #include <machine/md_var.h>
   57 #include <machine/ofw_machdep.h>
   58 #include <machine/platform.h>
   59 #include <machine/platformvar.h>
   60 #include <machine/smp.h>
   61 #include <machine/vmparam.h>
   62 
   63 #include "platform_if.h"
   64 
   65 static platform_def_t   *plat_def_impl;
   66 static platform_t       plat_obj;
   67 static struct kobj_ops  plat_kernel_kops;
   68 static struct platform_kobj     plat_kernel_obj;
   69 
   70 static char plat_name[64] = "";
   71 SYSCTL_STRING(_hw, OID_AUTO, platform, CTLFLAG_RD | CTLFLAG_TUN,
   72     plat_name, 0, "Platform currently in use");
   73 
   74 static struct mem_affinity mem_info[VM_PHYSSEG_MAX + 1];
   75 static int vm_locality_table[MAXMEMDOM * MAXMEMDOM];
   76 static struct mem_region pregions[PHYS_AVAIL_SZ];
   77 static struct numa_mem_region numa_pregions[PHYS_AVAIL_SZ];
   78 static struct mem_region aregions[PHYS_AVAIL_SZ];
   79 static int nnumapregions, npregions, naregions;
   80 
   81 /*
   82  * Memory region utilities: determine if two regions overlap,
   83  * and merge two overlapping regions into one
   84  */
   85 static int
   86 memr_overlap(struct mem_region *r1, struct mem_region *r2)
   87 {
   88         if ((r1->mr_start + r1->mr_size) < r2->mr_start ||
   89             (r2->mr_start + r2->mr_size) < r1->mr_start)
   90                 return (FALSE);
   91 
   92         return (TRUE);
   93 }
   94 
   95 static void
   96 memr_merge(struct mem_region *from, struct mem_region *to)
   97 {
   98         vm_offset_t end;
   99         end = uqmax(to->mr_start + to->mr_size, from->mr_start + from->mr_size);
  100         to->mr_start = uqmin(from->mr_start, to->mr_start);
  101         to->mr_size = end - to->mr_start;
  102 }
  103 
  104 /*
  105  * Quick sort callout for comparing memory regions.
  106  */
  107 static int
  108 mr_cmp(const void *a, const void *b)
  109 {
  110         const struct mem_region *regiona, *regionb;
  111 
  112         regiona = a;
  113         regionb = b;
  114         if (regiona->mr_start < regionb->mr_start)
  115                 return (-1);
  116         else if (regiona->mr_start > regionb->mr_start)
  117                 return (1);
  118         else
  119                 return (0);
  120 }
  121 
  122 void
  123 numa_mem_regions(struct numa_mem_region **phys, int *physsz)
  124 {
  125         struct mem_affinity *mi;
  126         int i, j, maxdom, ndomain, offset;
  127 
  128         nnumapregions = 0;
  129         PLATFORM_NUMA_MEM_REGIONS(plat_obj, numa_pregions, &nnumapregions);
  130 
  131         if (physsz != NULL)
  132                 *physsz = nnumapregions;
  133         if (phys != NULL)
  134                 *phys = numa_pregions;
  135         if (physsz == NULL || phys == NULL) {
  136                 printf("unset value\n");
  137                 return;
  138         }
  139         maxdom = 0;
  140         for (i = 0; i < nnumapregions; i++)
  141                 if (numa_pregions[i].mr_domain > maxdom)
  142                         maxdom = numa_pregions[i].mr_domain;
  143 
  144         mi = mem_info;
  145         for (i = 0; i < nnumapregions; i++, mi++) {
  146                 mi->start = numa_pregions[i].mr_start;
  147                 mi->end = numa_pregions[i].mr_start + numa_pregions[i].mr_size;
  148                 mi->domain = numa_pregions[i].mr_domain;
  149         }
  150         offset = 0;
  151         vm_locality_table[offset] = 10;
  152         ndomain = maxdom + 1;
  153         if (ndomain > 1) {
  154                 for (i = 0; i < ndomain; i++) {
  155                         for (j = 0; j < ndomain; j++) {
  156                                 /*
  157                                  * Not sure what these values should actually be
  158                                  */
  159                                 if (i == j)
  160                                         vm_locality_table[offset] = 10;
  161                                 else
  162                                         vm_locality_table[offset] = 21;
  163                                 offset++;
  164                         }
  165                 }
  166         }
  167         vm_phys_register_domains(ndomain, mem_info, vm_locality_table);
  168 }
  169 
  170 void
  171 mem_regions(struct mem_region **phys, int *physsz, struct mem_region **avail,
  172     int *availsz)
  173 {
  174         int i, j, still_merging;
  175 
  176         if (npregions == 0) {
  177                 PLATFORM_MEM_REGIONS(plat_obj, pregions, &npregions,
  178                     aregions, &naregions);
  179                 qsort(pregions, npregions, sizeof(*pregions), mr_cmp);
  180                 qsort(aregions, naregions, sizeof(*aregions), mr_cmp);
  181 
  182                 /* Remove overlapping available regions */
  183                 do {
  184                         still_merging = FALSE;
  185                         for (i = 0; i < naregions; i++) {
  186                                 if (aregions[i].mr_size == 0)
  187                                         continue;
  188                                 for (j = i+1; j < naregions; j++) {
  189                                         if (aregions[j].mr_size == 0)
  190                                                 continue;
  191                                         if (!memr_overlap(&aregions[j],
  192                                             &aregions[i]))
  193                                                 continue;
  194 
  195                                         memr_merge(&aregions[j], &aregions[i]);
  196                                         /* mark inactive */
  197                                         aregions[j].mr_size = 0;
  198                                         still_merging = TRUE;
  199                                 }
  200                         }
  201                 } while (still_merging == TRUE);
  202 
  203                 /* Collapse zero-length available regions */
  204                 for (i = 0; i < naregions; i++) {
  205                         if (aregions[i].mr_size == 0) {
  206                                 memcpy(&aregions[i], &aregions[i+1],
  207                                     (naregions - i - 1)*sizeof(*aregions));
  208                                 naregions--;
  209                                 i--;
  210                         }
  211                 }
  212         }
  213 
  214         if (phys != NULL)
  215                 *phys = pregions;
  216         if (avail != NULL)
  217                 *avail = aregions;
  218         if (physsz != NULL)
  219                 *physsz = npregions;
  220         if (availsz != NULL)
  221                 *availsz = naregions;
  222 }
  223 
  224 int
  225 mem_valid(vm_offset_t addr, int len)
  226 {
  227         int i;
  228 
  229         if (npregions == 0) {
  230                 struct mem_region *p, *a;
  231                 int na, np;
  232                 mem_regions(&p, &np, &a, &na);
  233         }
  234 
  235         for (i = 0; i < npregions; i++)
  236                 if ((addr >= pregions[i].mr_start)
  237                    && (addr + len <= pregions[i].mr_start + pregions[i].mr_size))
  238                         return (0);
  239 
  240         return (EFAULT);
  241 }
  242 
  243 vm_offset_t
  244 platform_real_maxaddr(void)
  245 {
  246         return (PLATFORM_REAL_MAXADDR(plat_obj));
  247 }
  248 
  249 const char *
  250 installed_platform()
  251 {
  252         return (plat_def_impl->name);
  253 }
  254 
  255 u_long
  256 platform_timebase_freq(struct cpuref *cpu)
  257 {
  258         return (PLATFORM_TIMEBASE_FREQ(plat_obj, cpu));
  259 }
  260 
  261 /*
  262  * Put the current CPU, as last step in suspend, to sleep
  263  */
  264 void
  265 platform_sleep()
  266 {
  267         PLATFORM_SLEEP(plat_obj);
  268 }
  269 
  270 int
  271 platform_smp_first_cpu(struct cpuref *cpu)
  272 {
  273         return (PLATFORM_SMP_FIRST_CPU(plat_obj, cpu));
  274 }
  275 
  276 int
  277 platform_smp_next_cpu(struct cpuref *cpu)
  278 {
  279         return (PLATFORM_SMP_NEXT_CPU(plat_obj, cpu));
  280 }
  281 
  282 int
  283 platform_smp_get_bsp(struct cpuref *cpu)
  284 {
  285         return (PLATFORM_SMP_GET_BSP(plat_obj, cpu));
  286 }
  287 
  288 int
  289 platform_smp_start_cpu(struct pcpu *cpu)
  290 {
  291         return (PLATFORM_SMP_START_CPU(plat_obj, cpu));
  292 }
  293 
  294 void
  295 platform_smp_ap_init()
  296 {
  297         PLATFORM_SMP_AP_INIT(plat_obj);
  298 }
  299 
  300 void
  301 platform_smp_probe_threads(void)
  302 {
  303         PLATFORM_SMP_PROBE_THREADS(plat_obj);
  304 }
  305 
  306 #ifdef SMP
  307 struct cpu_group *
  308 cpu_topo(void)
  309 {
  310         return (PLATFORM_SMP_TOPO(plat_obj));
  311 }
  312 #endif
  313 
  314 int
  315 platform_node_numa_domain(phandle_t node)
  316 {
  317         return (PLATFORM_NODE_NUMA_DOMAIN(plat_obj, node));
  318 }
  319 
  320 /*
  321  * Reset back to firmware.
  322  */
  323 void
  324 cpu_reset()
  325 {
  326         PLATFORM_RESET(plat_obj);
  327 }
  328 
  329 void platform_smp_timebase_sync(u_long tb, int ap)
  330 {
  331 
  332         PLATFORM_SMP_TIMEBASE_SYNC(plat_obj, tb, ap);
  333 }
  334 
  335 /*
  336  * Platform install routines. Highest priority wins, using the same
  337  * algorithm as bus attachment.
  338  */
  339 SET_DECLARE(platform_set, platform_def_t);
  340 
  341 void
  342 platform_probe_and_attach()
  343 {
  344         platform_def_t  **platpp, *platp;
  345         int             prio, best_prio;
  346 
  347         plat_obj = &plat_kernel_obj;
  348         best_prio = 0;
  349 
  350         /*
  351          * Try to locate the best platform kobj
  352          */
  353         SET_FOREACH(platpp, platform_set) {
  354                 platp = *platpp;
  355 
  356                 /*
  357                  * Take care of compiling the selected class, and
  358                  * then statically initialise the MMU object
  359                  */
  360                 kobj_class_compile_static(platp, &plat_kernel_kops);
  361                 kobj_init_static((kobj_t)plat_obj, platp);
  362 
  363                 prio = PLATFORM_PROBE(plat_obj);
  364 
  365                 /* Check for errors */
  366                 if (prio > 0)
  367                         continue;
  368 
  369                 /*
  370                  * Check if this module was specifically requested through
  371                  * the loader tunable we provide.
  372                  */
  373                 if (strcmp(platp->name,plat_name) == 0) {
  374                         plat_def_impl = platp;
  375                         break;
  376                 }
  377 
  378                 /* Otherwise, see if it is better than our current best */
  379                 if (plat_def_impl == NULL || prio > best_prio) {
  380                         best_prio = prio;
  381                         plat_def_impl = platp;
  382                 }
  383 
  384                 /*
  385                  * We can't free the KOBJ, since it is static. Reset the ops
  386                  * member of this class so that we can come back later.
  387                  */
  388                 platp->ops = NULL;
  389         }
  390 
  391         if (plat_def_impl == NULL)
  392                 panic("No platform module found!");
  393 
  394         /*
  395          * Recompile to make sure we ended with the
  396          * correct one, and then attach.
  397          */
  398 
  399         kobj_class_compile_static(plat_def_impl, &plat_kernel_kops);
  400         kobj_init_static((kobj_t)plat_obj, plat_def_impl);
  401 
  402         strlcpy(plat_name,plat_def_impl->name,sizeof(plat_name));
  403 
  404         PLATFORM_ATTACH(plat_obj);
  405 }

Cache object: b9227b596d91c916d1cf1baa9ba60a85


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