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/dev/acpica/acpi_pxm.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) 2010 Hudson River Trading LLC
    5  * Written by: John H. Baldwin <jhb@FreeBSD.org>
    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 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD$");
   32 
   33 #include "opt_vm.h"
   34 
   35 #include <sys/param.h>
   36 #include <sys/systm.h>
   37 #include <sys/bus.h>
   38 #include <sys/kernel.h>
   39 #include <sys/lock.h>
   40 #include <sys/mutex.h>
   41 #include <sys/smp.h>
   42 #include <sys/vmmeter.h>
   43 #include <vm/vm.h>
   44 #include <vm/pmap.h>
   45 #include <vm/vm_param.h>
   46 #include <vm/vm_page.h>
   47 #include <vm/vm_phys.h>
   48 
   49 #include <contrib/dev/acpica/include/acpi.h>
   50 #include <contrib/dev/acpica/include/aclocal.h>
   51 #include <contrib/dev/acpica/include/actables.h>
   52 
   53 #include <machine/md_var.h>
   54 
   55 #include <dev/acpica/acpivar.h>
   56 
   57 #if MAXMEMDOM > 1
   58 static struct cpu_info {
   59         int enabled:1;
   60         int has_memory:1;
   61         int domain;
   62         int id;
   63 } *cpus;
   64 
   65 static int max_cpus;
   66 static int last_cpu;
   67 
   68 struct mem_affinity mem_info[VM_PHYSSEG_MAX + 1];
   69 int num_mem;
   70 
   71 static ACPI_TABLE_SRAT *srat;
   72 static vm_paddr_t srat_physaddr;
   73 
   74 static int domain_pxm[MAXMEMDOM];
   75 static int ndomain;
   76 static vm_paddr_t maxphyaddr;
   77 
   78 static ACPI_TABLE_SLIT *slit;
   79 static vm_paddr_t slit_physaddr;
   80 static int vm_locality_table[MAXMEMDOM * MAXMEMDOM];
   81 
   82 static void     srat_walk_table(acpi_subtable_handler *handler, void *arg);
   83 
   84 /*
   85  * SLIT parsing.
   86  */
   87 
   88 static void
   89 slit_parse_table(ACPI_TABLE_SLIT *s)
   90 {
   91         int i, j;
   92         int i_domain, j_domain;
   93         int offset = 0;
   94         uint8_t e;
   95 
   96         /*
   97          * This maps the SLIT data into the VM-domain centric view.
   98          * There may be sparse entries in the PXM namespace, so
   99          * remap them to a VM-domain ID and if it doesn't exist,
  100          * skip it.
  101          *
  102          * It should result in a packed 2d array of VM-domain
  103          * locality information entries.
  104          */
  105 
  106         if (bootverbose)
  107                 printf("SLIT.Localities: %d\n", (int) s->LocalityCount);
  108         for (i = 0; i < s->LocalityCount; i++) {
  109                 i_domain = acpi_map_pxm_to_vm_domainid(i);
  110                 if (i_domain < 0)
  111                         continue;
  112 
  113                 if (bootverbose)
  114                         printf("%d: ", i);
  115                 for (j = 0; j < s->LocalityCount; j++) {
  116                         j_domain = acpi_map_pxm_to_vm_domainid(j);
  117                         if (j_domain < 0)
  118                                 continue;
  119                         e = s->Entry[i * s->LocalityCount + j];
  120                         if (bootverbose)
  121                                 printf("%d ", (int) e);
  122                         /* 255 == "no locality information" */
  123                         if (e == 255)
  124                                 vm_locality_table[offset] = -1;
  125                         else
  126                                 vm_locality_table[offset] = e;
  127                         offset++;
  128                 }
  129                 if (bootverbose)
  130                         printf("\n");
  131         }
  132 }
  133 
  134 /*
  135  * Look for an ACPI System Locality Distance Information Table ("SLIT")
  136  */
  137 static int
  138 parse_slit(void)
  139 {
  140 
  141         if (resource_disabled("slit", 0)) {
  142                 return (-1);
  143         }
  144 
  145         slit_physaddr = acpi_find_table(ACPI_SIG_SLIT);
  146         if (slit_physaddr == 0) {
  147                 return (-1);
  148         }
  149 
  150         /*
  151          * Make a pass over the table to populate the cpus[] and
  152          * mem_info[] tables.
  153          */
  154         slit = acpi_map_table(slit_physaddr, ACPI_SIG_SLIT);
  155         slit_parse_table(slit);
  156         acpi_unmap_table(slit);
  157         slit = NULL;
  158 
  159         return (0);
  160 }
  161 
  162 /*
  163  * SRAT parsing.
  164  */
  165 
  166 /*
  167  * Returns true if a memory range overlaps with at least one range in
  168  * phys_avail[].
  169  */
  170 static int
  171 overlaps_phys_avail(vm_paddr_t start, vm_paddr_t end)
  172 {
  173         int i;
  174 
  175         for (i = 0; phys_avail[i] != 0 && phys_avail[i + 1] != 0; i += 2) {
  176                 if (phys_avail[i + 1] <= start)
  177                         continue;
  178                 if (phys_avail[i] < end)
  179                         return (1);
  180                 break;
  181         }
  182         return (0);
  183 }
  184 
  185 /*
  186  * On x86 we can use the cpuid to index the cpus array, but on arm64
  187  * we have an ACPI Processor UID with a larger range.
  188  *
  189  * Use this variable to indicate if the cpus can be stored by index.
  190  */
  191 #ifdef __aarch64__
  192 static const int cpus_use_indexing = 0;
  193 #else
  194 static const int cpus_use_indexing = 1;
  195 #endif
  196 
  197 /*
  198  * Find CPU by processor ID (APIC ID on x86, Processor UID on arm64)
  199  */
  200 static struct cpu_info *
  201 cpu_find(int cpuid)
  202 {
  203         int i;
  204 
  205         if (cpus_use_indexing) {
  206                 if (cpuid <= last_cpu && cpus[cpuid].enabled)
  207                         return (&cpus[cpuid]);
  208         } else {
  209                 for (i = 0; i <= last_cpu; i++)
  210                         if (cpus[i].id == cpuid)
  211                                 return (&cpus[i]);
  212         }
  213         return (NULL);
  214 }
  215 
  216 /*
  217  * Find CPU by pcpu pointer.
  218  */
  219 static struct cpu_info *
  220 cpu_get_info(struct pcpu *pc)
  221 {
  222         struct cpu_info *cpup;
  223         int id;
  224 
  225 #ifdef __aarch64__
  226         id = pc->pc_acpi_id;
  227 #else
  228         id = pc->pc_apic_id;
  229 #endif
  230         cpup = cpu_find(id);
  231         if (cpup == NULL)
  232                 panic("SRAT: CPU with ID %u is not known", id);
  233         return (cpup);
  234 }
  235 
  236 /*
  237  * Add proximity information for a new CPU.
  238  */
  239 static struct cpu_info *
  240 cpu_add(int cpuid, int domain)
  241 {
  242         struct cpu_info *cpup;
  243 
  244         if (cpus_use_indexing) {
  245                 if (cpuid >= max_cpus)
  246                         return (NULL);
  247                 last_cpu = imax(last_cpu, cpuid);
  248                 cpup = &cpus[cpuid];
  249         } else {
  250                 if (last_cpu >= max_cpus - 1)
  251                         return (NULL);
  252                 cpup = &cpus[++last_cpu];
  253         }
  254         cpup->domain = domain;
  255         cpup->id = cpuid;
  256         cpup->enabled = 1;
  257         return (cpup);
  258 }
  259 
  260 static void
  261 srat_parse_entry(ACPI_SUBTABLE_HEADER *entry, void *arg)
  262 {
  263         ACPI_SRAT_CPU_AFFINITY *cpu;
  264         ACPI_SRAT_X2APIC_CPU_AFFINITY *x2apic;
  265         ACPI_SRAT_MEM_AFFINITY *mem;
  266         ACPI_SRAT_GICC_AFFINITY *gicc;
  267         static struct cpu_info *cpup;
  268         uint64_t base, length;
  269         int domain, i, slot;
  270 
  271         switch (entry->Type) {
  272         case ACPI_SRAT_TYPE_CPU_AFFINITY:
  273                 cpu = (ACPI_SRAT_CPU_AFFINITY *)entry;
  274                 domain = cpu->ProximityDomainLo |
  275                     cpu->ProximityDomainHi[0] << 8 |
  276                     cpu->ProximityDomainHi[1] << 16 |
  277                     cpu->ProximityDomainHi[2] << 24;
  278                 if (bootverbose)
  279                         printf("SRAT: Found CPU APIC ID %u domain %d: %s\n",
  280                             cpu->ApicId, domain,
  281                             (cpu->Flags & ACPI_SRAT_CPU_ENABLED) ?
  282                             "enabled" : "disabled");
  283                 if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED))
  284                         break;
  285                 cpup = cpu_find(cpu->ApicId);
  286                 if (cpup != NULL) {
  287                         printf("SRAT: Duplicate local APIC ID %u\n",
  288                             cpu->ApicId);
  289                         *(int *)arg = ENXIO;
  290                         break;
  291                 }
  292                 cpup = cpu_add(cpu->ApicId, domain);
  293                 if (cpup == NULL)
  294                         printf("SRAT: Ignoring local APIC ID %u (too high)\n",
  295                             cpu->ApicId);
  296                 break;
  297         case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY:
  298                 x2apic = (ACPI_SRAT_X2APIC_CPU_AFFINITY *)entry;
  299                 if (bootverbose)
  300                         printf("SRAT: Found CPU APIC ID %u domain %d: %s\n",
  301                             x2apic->ApicId, x2apic->ProximityDomain,
  302                             (x2apic->Flags & ACPI_SRAT_CPU_ENABLED) ?
  303                             "enabled" : "disabled");
  304                 if (!(x2apic->Flags & ACPI_SRAT_CPU_ENABLED))
  305                         break;
  306                 KASSERT(cpu_find(x2apic->ApicId) == NULL,
  307                     ("Duplicate local APIC ID %u", x2apic->ApicId));
  308                 cpup = cpu_add(x2apic->ApicId, x2apic->ProximityDomain);
  309                 if (cpup == NULL)
  310                         printf("SRAT: Ignoring local APIC ID %u (too high)\n",
  311                             x2apic->ApicId);
  312                 break;
  313         case ACPI_SRAT_TYPE_GICC_AFFINITY:
  314                 gicc = (ACPI_SRAT_GICC_AFFINITY *)entry;
  315                 if (bootverbose)
  316                         printf("SRAT: Found CPU UID %u domain %d: %s\n",
  317                             gicc->AcpiProcessorUid, gicc->ProximityDomain,
  318                             (gicc->Flags & ACPI_SRAT_GICC_ENABLED) ?
  319                             "enabled" : "disabled");
  320                 if (!(gicc->Flags & ACPI_SRAT_GICC_ENABLED))
  321                         break;
  322                 KASSERT(cpu_find(gicc->AcpiProcessorUid) == NULL,
  323                     ("Duplicate CPU UID %u", gicc->AcpiProcessorUid));
  324                 cpup = cpu_add(gicc->AcpiProcessorUid, gicc->ProximityDomain);
  325                 if (cpup == NULL)
  326                         printf("SRAT: Ignoring CPU UID %u (too high)\n",
  327                             gicc->AcpiProcessorUid);
  328                 break;
  329         case ACPI_SRAT_TYPE_MEMORY_AFFINITY:
  330                 mem = (ACPI_SRAT_MEM_AFFINITY *)entry;
  331                 base = mem->BaseAddress;
  332                 length = mem->Length;
  333                 domain = mem->ProximityDomain;
  334 
  335                 if (bootverbose)
  336                         printf(
  337                     "SRAT: Found memory domain %d addr 0x%jx len 0x%jx: %s\n",
  338                             domain, (uintmax_t)base, (uintmax_t)length,
  339                             (mem->Flags & ACPI_SRAT_MEM_ENABLED) ?
  340                             "enabled" : "disabled");
  341                 if (!(mem->Flags & ACPI_SRAT_MEM_ENABLED))
  342                         break;
  343                 if (base >= maxphyaddr ||
  344                     !overlaps_phys_avail(base, base + length)) {
  345                         printf("SRAT: Ignoring memory at addr 0x%jx\n",
  346                             (uintmax_t)base);
  347                         break;
  348                 }
  349                 if (num_mem == VM_PHYSSEG_MAX) {
  350                         printf("SRAT: Too many memory regions\n");
  351                         *(int *)arg = ENXIO;
  352                         break;
  353                 }
  354                 slot = num_mem;
  355                 for (i = 0; i < num_mem; i++) {
  356                         if (mem_info[i].domain == domain) {
  357                                 /* Try to extend an existing segment. */
  358                                 if (base == mem_info[i].end) {
  359                                         mem_info[i].end += length;
  360                                         return;
  361                                 }
  362                                 if (base + length == mem_info[i].start) {
  363                                         mem_info[i].start -= length;
  364                                         return;
  365                                 }
  366                         }
  367                         if (mem_info[i].end <= base)
  368                                 continue;
  369                         if (mem_info[i].start < base + length) {
  370                                 printf("SRAT: Overlapping memory entries\n");
  371                                 *(int *)arg = ENXIO;
  372                                 return;
  373                         }
  374                         slot = i;
  375                 }
  376                 for (i = num_mem; i > slot; i--)
  377                         mem_info[i] = mem_info[i - 1];
  378                 mem_info[slot].start = base;
  379                 mem_info[slot].end = base + length;
  380                 mem_info[slot].domain = domain;
  381                 num_mem++;
  382                 break;
  383         }
  384 }
  385 
  386 /*
  387  * Ensure each memory domain has at least one CPU and that each CPU
  388  * has at least one memory domain.
  389  */
  390 static int
  391 check_domains(void)
  392 {
  393         int found, i, j;
  394 
  395         for (i = 0; i < num_mem; i++) {
  396                 found = 0;
  397                 for (j = 0; j <= last_cpu; j++)
  398                         if (cpus[j].enabled &&
  399                             cpus[j].domain == mem_info[i].domain) {
  400                                 cpus[j].has_memory = 1;
  401                                 found++;
  402                         }
  403                 if (!found) {
  404                         printf("SRAT: No CPU found for memory domain %d\n",
  405                             mem_info[i].domain);
  406                         return (ENXIO);
  407                 }
  408         }
  409         for (i = 0; i <= last_cpu; i++)
  410                 if (cpus[i].enabled && !cpus[i].has_memory) {
  411                         found = 0;
  412                         for (j = 0; j < num_mem && !found; j++) {
  413                                 if (mem_info[j].domain == cpus[i].domain)
  414                                         found = 1;
  415                         }
  416                         if (!found) {
  417                                 if (bootverbose)
  418                                         printf("SRAT: mem dom %d is empty\n",
  419                                             cpus[i].domain);
  420                                 mem_info[num_mem].start = 0;
  421                                 mem_info[num_mem].end = 0;
  422                                 mem_info[num_mem].domain = cpus[i].domain;
  423                                 num_mem++;
  424                         }
  425                 }
  426         return (0);
  427 }
  428 
  429 /*
  430  * Check that the SRAT memory regions cover all of the regions in
  431  * phys_avail[].
  432  */
  433 static int
  434 check_phys_avail(void)
  435 {
  436         vm_paddr_t address;
  437         int i, j;
  438 
  439         /* j is the current offset into phys_avail[]. */
  440         address = phys_avail[0];
  441         j = 0;
  442         for (i = 0; i < num_mem; i++) {
  443                 /*
  444                  * Consume as many phys_avail[] entries as fit in this
  445                  * region.
  446                  */
  447                 while (address >= mem_info[i].start &&
  448                     address <= mem_info[i].end) {
  449                         /*
  450                          * If we cover the rest of this phys_avail[] entry,
  451                          * advance to the next entry.
  452                          */
  453                         if (phys_avail[j + 1] <= mem_info[i].end) {
  454                                 j += 2;
  455                                 if (phys_avail[j] == 0 &&
  456                                     phys_avail[j + 1] == 0) {
  457                                         return (0);
  458                                 }
  459                                 address = phys_avail[j];
  460                         } else
  461                                 address = mem_info[i].end + 1;
  462                 }
  463         }
  464         printf("SRAT: No memory region found for 0x%jx - 0x%jx\n",
  465             (uintmax_t)phys_avail[j], (uintmax_t)phys_avail[j + 1]);
  466         return (ENXIO);
  467 }
  468 
  469 /*
  470  * Renumber the memory domains to be compact and zero-based if not
  471  * already.  Returns an error if there are too many domains.
  472  */
  473 static int
  474 renumber_domains(void)
  475 {
  476         int i, j, slot;
  477 
  478         /* Enumerate all the domains. */
  479         ndomain = 0;
  480         for (i = 0; i < num_mem; i++) {
  481                 /* See if this domain is already known. */
  482                 for (j = 0; j < ndomain; j++) {
  483                         if (domain_pxm[j] >= mem_info[i].domain)
  484                                 break;
  485                 }
  486                 if (j < ndomain && domain_pxm[j] == mem_info[i].domain)
  487                         continue;
  488 
  489                 if (ndomain >= MAXMEMDOM) {
  490                         ndomain = 1;
  491                         printf("SRAT: Too many memory domains\n");
  492                         return (EFBIG);
  493                 }
  494 
  495                 /* Insert the new domain at slot 'j'. */
  496                 slot = j;
  497                 for (j = ndomain; j > slot; j--)
  498                         domain_pxm[j] = domain_pxm[j - 1];
  499                 domain_pxm[slot] = mem_info[i].domain;
  500                 ndomain++;
  501         }
  502 
  503         /* Renumber each domain to its index in the sorted 'domain_pxm' list. */
  504         for (i = 0; i < ndomain; i++) {
  505                 /*
  506                  * If the domain is already the right value, no need
  507                  * to renumber.
  508                  */
  509                 if (domain_pxm[i] == i)
  510                         continue;
  511 
  512                 /* Walk the cpu[] and mem_info[] arrays to renumber. */
  513                 for (j = 0; j < num_mem; j++)
  514                         if (mem_info[j].domain == domain_pxm[i])
  515                                 mem_info[j].domain = i;
  516                 for (j = 0; j <= last_cpu; j++)
  517                         if (cpus[j].enabled && cpus[j].domain == domain_pxm[i])
  518                                 cpus[j].domain = i;
  519         }
  520 
  521         return (0);
  522 }
  523 
  524 /*
  525  * Look for an ACPI System Resource Affinity Table ("SRAT"),
  526  * allocate space for cpu information, and initialize globals.
  527  */
  528 int
  529 acpi_pxm_init(int ncpus, vm_paddr_t maxphys)
  530 {
  531         unsigned int idx, size;
  532         vm_paddr_t addr;
  533 
  534         if (resource_disabled("srat", 0))
  535                 return (-1);
  536 
  537         max_cpus = ncpus;
  538         last_cpu = -1;
  539         maxphyaddr = maxphys;
  540         srat_physaddr = acpi_find_table(ACPI_SIG_SRAT);
  541         if (srat_physaddr == 0)
  542                 return (-1);
  543 
  544         /*
  545          * Allocate data structure:
  546          *
  547          * Find the last physical memory region and steal some memory from
  548          * it. This is done because at this point in the boot process
  549          * malloc is still not usable.
  550          */
  551         for (idx = 0; phys_avail[idx + 1] != 0; idx += 2);
  552         KASSERT(idx != 0, ("phys_avail is empty!"));
  553         idx -= 2;
  554 
  555         size =  sizeof(*cpus) * max_cpus;
  556         addr = trunc_page(phys_avail[idx + 1] - size);
  557         KASSERT(addr >= phys_avail[idx],
  558             ("Not enough memory for SRAT table items"));
  559         phys_avail[idx + 1] = addr - 1;
  560 
  561         /*
  562          * We cannot rely on PHYS_TO_DMAP because this code is also used in
  563          * i386, so use pmap_mapbios to map the memory, this will end up using
  564          * the default memory attribute (WB), and the DMAP when available.
  565          */
  566         cpus = (struct cpu_info *)pmap_mapbios(addr, size);
  567         bzero(cpus, size);
  568         return (0);
  569 }
  570 
  571 static int
  572 parse_srat(void)
  573 {
  574         int error;
  575 
  576         /*
  577          * Make a pass over the table to populate the cpus[] and
  578          * mem_info[] tables.
  579          */
  580         srat = acpi_map_table(srat_physaddr, ACPI_SIG_SRAT);
  581         error = 0;
  582         srat_walk_table(srat_parse_entry, &error);
  583         acpi_unmap_table(srat);
  584         srat = NULL;
  585         if (error || check_domains() != 0 || check_phys_avail() != 0 ||
  586             renumber_domains() != 0) {
  587                 srat_physaddr = 0;
  588                 return (-1);
  589         }
  590 
  591         return (0);
  592 }
  593 
  594 static void
  595 init_mem_locality(void)
  596 {
  597         int i;
  598 
  599         /*
  600          * For now, assume -1 == "no locality information for
  601          * this pairing.
  602          */
  603         for (i = 0; i < MAXMEMDOM * MAXMEMDOM; i++)
  604                 vm_locality_table[i] = -1;
  605 }
  606 
  607 /*
  608  * Parse SRAT and SLIT to save proximity info. Don't do
  609  * anything if SRAT is not available.
  610  */
  611 void
  612 acpi_pxm_parse_tables(void)
  613 {
  614 
  615         if (srat_physaddr == 0)
  616                 return;
  617         if (parse_srat() < 0)
  618                 return;
  619         init_mem_locality();
  620         (void)parse_slit();
  621 }
  622 
  623 /*
  624  * Use saved data from SRAT/SLIT to update memory locality.
  625  */
  626 void
  627 acpi_pxm_set_mem_locality(void)
  628 {
  629 
  630         if (srat_physaddr == 0)
  631                 return;
  632         vm_phys_register_domains(ndomain, mem_info, vm_locality_table);
  633 }
  634 
  635 static void
  636 srat_walk_table(acpi_subtable_handler *handler, void *arg)
  637 {
  638 
  639         acpi_walk_subtables(srat + 1, (char *)srat + srat->Header.Length,
  640             handler, arg);
  641 }
  642 
  643 /*
  644  * Set up per-CPU domain IDs from information saved in 'cpus' and tear down data
  645  * structures allocated by acpi_pxm_init().
  646  */
  647 void
  648 acpi_pxm_set_cpu_locality(void)
  649 {
  650         struct cpu_info *cpu;
  651         struct pcpu *pc;
  652         u_int i;
  653 
  654         if (srat_physaddr == 0)
  655                 return;
  656         for (i = 0; i < MAXCPU; i++) {
  657                 if (CPU_ABSENT(i))
  658                         continue;
  659                 pc = pcpu_find(i);
  660                 KASSERT(pc != NULL, ("no pcpu data for CPU %u", i));
  661                 cpu = cpu_get_info(pc);
  662                 pc->pc_domain = vm_ndomains > 1 ? cpu->domain : 0;
  663                 CPU_SET(i, &cpuset_domain[pc->pc_domain]);
  664                 if (bootverbose)
  665                         printf("SRAT: CPU %u has memory domain %d\n", i,
  666                             pc->pc_domain);
  667         }
  668         /* XXXMJ the page is leaked. */
  669         pmap_unmapbios(cpus, sizeof(*cpus) * max_cpus);
  670         srat_physaddr = 0;
  671         cpus = NULL;
  672 }
  673 
  674 int
  675 acpi_pxm_get_cpu_locality(int apic_id)
  676 {
  677         struct cpu_info *cpu;
  678 
  679         cpu = cpu_find(apic_id);
  680         if (cpu == NULL)
  681                 panic("SRAT: CPU with ID %u is not known", apic_id);
  682         return (cpu->domain);
  683 }
  684 
  685 /*
  686  * Map a _PXM value to a VM domain ID.
  687  *
  688  * Returns the domain ID, or -1 if no domain ID was found.
  689  */
  690 int
  691 acpi_map_pxm_to_vm_domainid(int pxm)
  692 {
  693         int i;
  694 
  695         for (i = 0; i < ndomain; i++) {
  696                 if (domain_pxm[i] == pxm)
  697                         return (vm_ndomains > 1 ? i : 0);
  698         }
  699 
  700         return (-1);
  701 }
  702 
  703 #else /* MAXMEMDOM == 1 */
  704 
  705 int
  706 acpi_map_pxm_to_vm_domainid(int pxm)
  707 {
  708 
  709         return (-1);
  710 }
  711 
  712 #endif /* MAXMEMDOM > 1 */

Cache object: eaf5c37b0743d3683ed4b5810752c928


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