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/x86/acpica/madt.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) 2003 John Baldwin <jhb@FreeBSD.org>
    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  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  */
   27 
   28 #include <sys/cdefs.h>
   29 __FBSDID("$FreeBSD$");
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/bus.h>
   34 #include <sys/kernel.h>
   35 #include <sys/limits.h>
   36 #include <sys/malloc.h>
   37 #include <sys/smp.h>
   38 #include <vm/vm.h>
   39 #include <vm/pmap.h>
   40 
   41 #include <x86/apicreg.h>
   42 #include <machine/intr_machdep.h>
   43 #include <x86/apicvar.h>
   44 #include <machine/md_var.h>
   45 #include <x86/vmware.h>
   46 
   47 #include <contrib/dev/acpica/include/acpi.h>
   48 #include <contrib/dev/acpica/include/aclocal.h>
   49 #include <contrib/dev/acpica/include/actables.h>
   50 
   51 #include <dev/acpica/acpivar.h>
   52 #include <dev/pci/pcivar.h>
   53 
   54 /* These two arrays are indexed by APIC IDs. */
   55 static struct {
   56         void *io_apic;
   57         UINT32 io_vector;
   58 } *ioapics;
   59 
   60 static struct lapic_info {
   61         u_int la_enabled;
   62         u_int la_acpi_id;
   63 } *lapics;
   64 
   65 int madt_found_sci_override;
   66 static ACPI_TABLE_MADT *madt;
   67 static vm_paddr_t madt_physaddr;
   68 static vm_offset_t madt_length;
   69 
   70 static MALLOC_DEFINE(M_MADT, "madt_table", "ACPI MADT Table Items");
   71 
   72 static enum intr_polarity interrupt_polarity(UINT16 IntiFlags, UINT8 Source);
   73 static enum intr_trigger interrupt_trigger(UINT16 IntiFlags, UINT8 Source);
   74 static int      madt_find_cpu(u_int acpi_id, u_int *apic_id);
   75 static int      madt_find_interrupt(int intr, void **apic, u_int *pin);
   76 static void     madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg);
   77 static void     madt_parse_interrupt_override(
   78                     ACPI_MADT_INTERRUPT_OVERRIDE *intr);
   79 static void     madt_parse_ints(ACPI_SUBTABLE_HEADER *entry,
   80                     void *arg __unused);
   81 static void     madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi);
   82 static void     madt_parse_nmi(ACPI_MADT_NMI_SOURCE *nmi);
   83 static int      madt_probe(void);
   84 static int      madt_probe_cpus(void);
   85 static void     madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry,
   86                     void *arg __unused);
   87 static void     madt_setup_cpus_handler(ACPI_SUBTABLE_HEADER *entry,
   88                     void *arg __unused);
   89 static void     madt_register(void *dummy);
   90 static int      madt_setup_local(void);
   91 static int      madt_setup_io(void);
   92 static void     madt_walk_table(acpi_subtable_handler *handler, void *arg);
   93 
   94 static struct apic_enumerator madt_enumerator = {
   95         .apic_name = "MADT",
   96         .apic_probe = madt_probe,
   97         .apic_probe_cpus = madt_probe_cpus,
   98         .apic_setup_local = madt_setup_local,
   99         .apic_setup_io = madt_setup_io
  100 };
  101 
  102 /*
  103  * Look for an ACPI Multiple APIC Description Table ("APIC")
  104  */
  105 static int
  106 madt_probe(void)
  107 {
  108 
  109         madt_physaddr = acpi_find_table(ACPI_SIG_MADT);
  110         if (madt_physaddr == 0)
  111                 return (ENXIO);
  112         return (-50);
  113 }
  114 
  115 /*
  116  * Run through the MP table enumerating CPUs.
  117  */
  118 static int
  119 madt_probe_cpus(void)
  120 {
  121 
  122         madt = acpi_map_table(madt_physaddr, ACPI_SIG_MADT);
  123         madt_length = madt->Header.Length;
  124         KASSERT(madt != NULL, ("Unable to re-map MADT"));
  125         madt_walk_table(madt_probe_cpus_handler, NULL);
  126         acpi_unmap_table(madt);
  127         madt = NULL;
  128         return (0);
  129 }
  130 
  131 static const char *x2apic_sandy_dis[] = {
  132         "LENOVO",
  133         "ASUSTeK Computer Inc.",
  134         "SAMSUNG ELECTRONICS CO., LTD.",
  135 };
  136 
  137 /*
  138  * Automatically detect several configurations where x2APIC mode is
  139  * known to cause troubles.  User can override the setting with
  140  * hw.x2apic_enable tunable.
  141  */
  142 static const char *
  143 madt_x2apic_disable_reason(void)
  144 {
  145         ACPI_TABLE_DMAR *dmartbl;
  146         vm_paddr_t dmartbl_physaddr;
  147         const char *reason;
  148         char *hw_vendor;
  149         u_int p[4];
  150         int i;
  151 
  152         reason = NULL;
  153 
  154         dmartbl_physaddr = acpi_find_table(ACPI_SIG_DMAR);
  155         if (dmartbl_physaddr != 0) {
  156                 dmartbl = acpi_map_table(dmartbl_physaddr, ACPI_SIG_DMAR);
  157                 if ((dmartbl->Flags & ACPI_DMAR_X2APIC_OPT_OUT) != 0)
  158                         reason = "by DMAR table";
  159                 acpi_unmap_table(dmartbl);
  160                 if (reason != NULL)
  161                         return (reason);
  162         }
  163 
  164         if (vm_guest == VM_GUEST_VMWARE) {
  165                 vmware_hvcall(VMW_HVCMD_GETVCPU_INFO, p);
  166                 if ((p[0] & VMW_VCPUINFO_VCPU_RESERVED) != 0 ||
  167                     (p[0] & VMW_VCPUINFO_LEGACY_X2APIC) == 0)
  168                         return ("inside VMWare without intr redirection");
  169         }
  170 
  171         if (vm_guest == VM_GUEST_NO &&
  172             CPUID_TO_FAMILY(cpu_id) == 0x6 &&
  173             CPUID_TO_MODEL(cpu_id) == 0x2a) {
  174                 hw_vendor = kern_getenv("smbios.planar.maker");
  175                 /*
  176                  * It seems that some SandyBridge-based notebook
  177                  * BIOSes have a bug which prevents booting AP in
  178                  * x2APIC mode.  Since the only way to detect mobile
  179                  * CPU is to check northbridge pci id, which cannot be
  180                  * done that early, disable x2APIC for all such
  181                  * machines.
  182                  */
  183                 if (hw_vendor != NULL) {
  184                         for (i = 0; i < nitems(x2apic_sandy_dis); i++) {
  185                                 if (strcmp(hw_vendor, x2apic_sandy_dis[i]) ==
  186                                     0) {
  187                                         reason =
  188                                 "for a suspected SandyBridge BIOS bug";
  189                                         break;
  190                                 }
  191                         }
  192                         freeenv(hw_vendor);
  193                 }
  194                 if (reason != NULL)
  195                         return (reason);
  196         }
  197 
  198         return (NULL);
  199 }
  200 
  201 /*
  202  * Initialize the local APIC on the BSP.
  203  */
  204 static int
  205 madt_setup_local(void)
  206 {
  207         const char *reason;
  208         int user_x2apic;
  209         bool bios_x2apic;
  210 
  211         if ((cpu_feature2 & CPUID2_X2APIC) != 0) {
  212                 reason = madt_x2apic_disable_reason();
  213                 bios_x2apic = lapic_is_x2apic();
  214                 if (reason != NULL && bios_x2apic) {
  215                         if (bootverbose)
  216                                 printf("x2APIC should be disabled %s but "
  217                                     "already enabled by BIOS; enabling.\n",
  218                                      reason);
  219                         reason = NULL;
  220                 }
  221                 if (reason == NULL)
  222                         x2apic_mode = 1;
  223                 else if (bootverbose)
  224                         printf("x2APIC available but disabled %s\n", reason);
  225                 user_x2apic = x2apic_mode;
  226                 TUNABLE_INT_FETCH("hw.x2apic_enable", &user_x2apic);
  227                 if (user_x2apic != x2apic_mode) {
  228                         if (bios_x2apic && !user_x2apic)
  229                                 printf("x2APIC disabled by tunable and "
  230                                     "enabled by BIOS; ignoring tunable.");
  231                         else
  232                                 x2apic_mode = user_x2apic;
  233                 }
  234         }
  235 
  236         /*
  237          * Truncate max_apic_id if not in x2APIC mode. Some structures
  238          * will already be allocated with the previous max_apic_id, but
  239          * at least we can prevent wasting more memory elsewhere.
  240          */
  241         if (!x2apic_mode)
  242                 max_apic_id = min(max_apic_id, xAPIC_MAX_APIC_ID);
  243 
  244         madt = pmap_mapbios(madt_physaddr, madt_length);
  245         lapics = malloc(sizeof(*lapics) * (max_apic_id + 1), M_MADT,
  246             M_WAITOK | M_ZERO);
  247         madt_walk_table(madt_setup_cpus_handler, NULL);
  248 
  249         lapic_init(madt->Address);
  250         printf("ACPI APIC Table: <%.*s %.*s>\n",
  251             (int)sizeof(madt->Header.OemId), madt->Header.OemId,
  252             (int)sizeof(madt->Header.OemTableId), madt->Header.OemTableId);
  253 
  254         /*
  255          * We ignore 64-bit local APIC override entries.  Should we
  256          * perhaps emit a warning here if we find one?
  257          */
  258         return (0);
  259 }
  260 
  261 /*
  262  * Enumerate I/O APICs and setup interrupt sources.
  263  */
  264 static int
  265 madt_setup_io(void)
  266 {
  267         void *ioapic;
  268         u_int pin;
  269         int i;
  270 
  271         KASSERT(lapics != NULL, ("local APICs not initialized"));
  272 
  273         /* Try to initialize ACPI so that we can access the FADT. */
  274         i = acpi_Startup();
  275         if (ACPI_FAILURE(i)) {
  276                 printf("MADT: ACPI Startup failed with %s\n",
  277                     AcpiFormatException(i));
  278                 printf("Try disabling either ACPI or apic support.\n");
  279                 panic("Using MADT but ACPI doesn't work");
  280         }
  281 
  282         ioapics = malloc(sizeof(*ioapics) * (IOAPIC_MAX_ID + 1), M_MADT,
  283             M_WAITOK | M_ZERO);
  284 
  285         /* First, we run through adding I/O APIC's. */
  286         madt_walk_table(madt_parse_apics, NULL);
  287 
  288         /* Second, we run through the table tweaking interrupt sources. */
  289         madt_walk_table(madt_parse_ints, NULL);
  290 
  291         /*
  292          * If there was not an explicit override entry for the SCI,
  293          * force it to use level trigger and active-low polarity.
  294          */
  295         if (!madt_found_sci_override) {
  296                 if (madt_find_interrupt(AcpiGbl_FADT.SciInterrupt, &ioapic,
  297                     &pin) != 0)
  298                         printf("MADT: Could not find APIC for SCI IRQ %u\n",
  299                             AcpiGbl_FADT.SciInterrupt);
  300                 else {
  301                         printf(
  302         "MADT: Forcing active-low polarity and level trigger for SCI\n");
  303                         ioapic_set_polarity(ioapic, pin, INTR_POLARITY_LOW);
  304                         ioapic_set_triggermode(ioapic, pin, INTR_TRIGGER_LEVEL);
  305                 }
  306         }
  307 
  308         /* Third, we register all the I/O APIC's. */
  309         for (i = 0; i <= IOAPIC_MAX_ID; i++)
  310                 if (ioapics[i].io_apic != NULL)
  311                         ioapic_register(ioapics[i].io_apic);
  312 
  313         /* Finally, we throw the switch to enable the I/O APIC's. */
  314         acpi_SetDefaultIntrModel(ACPI_INTR_APIC);
  315 
  316         free(ioapics, M_MADT);
  317         ioapics = NULL;
  318 
  319         /* NB: this is the last use of the lapics array. */
  320         free(lapics, M_MADT);
  321         lapics = NULL;
  322 
  323         return (0);
  324 }
  325 
  326 static void
  327 madt_register(void *dummy __unused)
  328 {
  329 
  330         apic_register_enumerator(&madt_enumerator);
  331 }
  332 SYSINIT(madt_register, SI_SUB_TUNABLES - 1, SI_ORDER_FIRST, madt_register, NULL);
  333 
  334 /*
  335  * Call the handler routine for each entry in the MADT table.
  336  */
  337 static void
  338 madt_walk_table(acpi_subtable_handler *handler, void *arg)
  339 {
  340 
  341         acpi_walk_subtables(madt + 1, (char *)madt + madt->Header.Length,
  342             handler, arg);
  343 }
  344 
  345 static void
  346 madt_parse_cpu(unsigned int apic_id, unsigned int flags)
  347 {
  348 
  349         if (!(flags & ACPI_MADT_ENABLED) ||
  350 #ifdef SMP
  351             mp_ncpus == MAXCPU ||
  352 #endif
  353             apic_id > MAX_APIC_ID)
  354                 return;
  355 
  356 #ifdef SMP
  357         mp_ncpus++;
  358         mp_maxid = mp_ncpus - 1;
  359 #endif
  360         max_apic_id = max(apic_id, max_apic_id);
  361 }
  362 
  363 static void
  364 madt_add_cpu(u_int acpi_id, u_int apic_id, u_int flags)
  365 {
  366         struct lapic_info *la;
  367 
  368         /*
  369          * The MADT does not include a BSP flag, so we have to let the
  370          * MP code figure out which CPU is the BSP on its own.
  371          */
  372         if (bootverbose)
  373                 printf("MADT: Found CPU APIC ID %u ACPI ID %u: %s\n",
  374                     apic_id, acpi_id, flags & ACPI_MADT_ENABLED ?
  375                     "enabled" : "disabled");
  376         if (!(flags & ACPI_MADT_ENABLED))
  377                 return;
  378         if (apic_id > max_apic_id) {
  379                 printf("MADT: Ignoring local APIC ID %u (too high)\n",
  380                     apic_id);
  381                 return;
  382         }
  383 
  384         la = &lapics[apic_id];
  385         KASSERT(la->la_enabled == 0, ("Duplicate local APIC ID %u", apic_id));
  386         la->la_enabled = 1;
  387         la->la_acpi_id = acpi_id;
  388         lapic_create(apic_id, 0);
  389 }
  390 
  391 static void
  392 madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
  393 {
  394         ACPI_MADT_LOCAL_APIC *proc;
  395         ACPI_MADT_LOCAL_X2APIC *x2apic;
  396 
  397         switch (entry->Type) {
  398         case ACPI_MADT_TYPE_LOCAL_APIC:
  399                 proc = (ACPI_MADT_LOCAL_APIC *)entry;
  400                 madt_parse_cpu(proc->Id, proc->LapicFlags);
  401                 break;
  402         case ACPI_MADT_TYPE_LOCAL_X2APIC:
  403                 x2apic = (ACPI_MADT_LOCAL_X2APIC *)entry;
  404                 madt_parse_cpu(x2apic->LocalApicId, x2apic->LapicFlags);
  405                 break;
  406         }
  407 }
  408 
  409 static void
  410 madt_setup_cpus_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
  411 {
  412         ACPI_MADT_LOCAL_APIC *proc;
  413         ACPI_MADT_LOCAL_X2APIC *x2apic;
  414 
  415         switch (entry->Type) {
  416         case ACPI_MADT_TYPE_LOCAL_APIC:
  417                 proc = (ACPI_MADT_LOCAL_APIC *)entry;
  418                 madt_add_cpu(proc->ProcessorId, proc->Id, proc->LapicFlags);
  419                 break;
  420         case ACPI_MADT_TYPE_LOCAL_X2APIC:
  421                 x2apic = (ACPI_MADT_LOCAL_X2APIC *)entry;
  422                 madt_add_cpu(x2apic->Uid, x2apic->LocalApicId,
  423                     x2apic->LapicFlags);
  424                 break;
  425         }
  426 }
  427 
  428 /*
  429  * Add an I/O APIC from an entry in the table.
  430  */
  431 static void
  432 madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
  433 {
  434         ACPI_MADT_IO_APIC *apic;
  435 
  436         switch (entry->Type) {
  437         case ACPI_MADT_TYPE_IO_APIC:
  438                 apic = (ACPI_MADT_IO_APIC *)entry;
  439                 if (bootverbose)
  440                         printf(
  441                             "MADT: Found IO APIC ID %u, Interrupt %u at %p\n",
  442                             apic->Id, apic->GlobalIrqBase,
  443                             (void *)(uintptr_t)apic->Address);
  444                 if (apic->Id > IOAPIC_MAX_ID)
  445                         panic("%s: I/O APIC ID %u too high", __func__,
  446                             apic->Id);
  447                 if (ioapics[apic->Id].io_apic != NULL)
  448                         panic("%s: Double APIC ID %u", __func__, apic->Id);
  449                 ioapics[apic->Id].io_apic = ioapic_create(apic->Address,
  450                     apic->Id, apic->GlobalIrqBase);
  451                 ioapics[apic->Id].io_vector = apic->GlobalIrqBase;
  452                 break;
  453         default:
  454                 break;
  455         }
  456 }
  457 
  458 /*
  459  * Determine properties of an interrupt source.  Note that for ACPI these
  460  * functions are only used for ISA interrupts, so we assume ISA bus values
  461  * (Active Hi, Edge Triggered) for conforming values except for the ACPI
  462  * SCI for which we use Active Lo, Level Triggered.
  463  */
  464 static enum intr_polarity
  465 interrupt_polarity(UINT16 IntiFlags, UINT8 Source)
  466 {
  467 
  468         switch (IntiFlags & ACPI_MADT_POLARITY_MASK) {
  469         default:
  470                 printf("WARNING: Bogus Interrupt Polarity. Assume CONFORMS\n");
  471                 /* FALLTHROUGH*/
  472         case ACPI_MADT_POLARITY_CONFORMS:
  473                 if (Source == AcpiGbl_FADT.SciInterrupt)
  474                         return (INTR_POLARITY_LOW);
  475                 else
  476                         return (INTR_POLARITY_HIGH);
  477         case ACPI_MADT_POLARITY_ACTIVE_HIGH:
  478                 return (INTR_POLARITY_HIGH);
  479         case ACPI_MADT_POLARITY_ACTIVE_LOW:
  480                 return (INTR_POLARITY_LOW);
  481         }
  482 }
  483 
  484 static enum intr_trigger
  485 interrupt_trigger(UINT16 IntiFlags, UINT8 Source)
  486 {
  487 
  488         switch (IntiFlags & ACPI_MADT_TRIGGER_MASK) {
  489         default:
  490                 printf("WARNING: Bogus Interrupt Trigger Mode. Assume CONFORMS.\n");
  491                 /*FALLTHROUGH*/
  492         case ACPI_MADT_TRIGGER_CONFORMS:
  493                 if (Source == AcpiGbl_FADT.SciInterrupt)
  494                         return (INTR_TRIGGER_LEVEL);
  495                 else
  496                         return (INTR_TRIGGER_EDGE);
  497         case ACPI_MADT_TRIGGER_EDGE:
  498                 return (INTR_TRIGGER_EDGE);
  499         case ACPI_MADT_TRIGGER_LEVEL:
  500                 return (INTR_TRIGGER_LEVEL);
  501         }
  502 }
  503 
  504 /*
  505  * Find the local APIC ID associated with a given ACPI Processor ID.
  506  */
  507 static int
  508 madt_find_cpu(u_int acpi_id, u_int *apic_id)
  509 {
  510         int i;
  511 
  512         for (i = 0; i <= max_apic_id; i++) {
  513                 if (!lapics[i].la_enabled)
  514                         continue;
  515                 if (lapics[i].la_acpi_id != acpi_id)
  516                         continue;
  517                 *apic_id = i;
  518                 return (0);
  519         }
  520         return (ENOENT);
  521 }
  522 
  523 /*
  524  * Find the IO APIC and pin on that APIC associated with a given global
  525  * interrupt.
  526  */
  527 static int
  528 madt_find_interrupt(int intr, void **apic, u_int *pin)
  529 {
  530         int i, best;
  531 
  532         best = -1;
  533         for (i = 0; i <= IOAPIC_MAX_ID; i++) {
  534                 if (ioapics[i].io_apic == NULL ||
  535                     ioapics[i].io_vector > intr)
  536                         continue;
  537                 if (best == -1 ||
  538                     ioapics[best].io_vector < ioapics[i].io_vector)
  539                         best = i;
  540         }
  541         if (best == -1)
  542                 return (ENOENT);
  543         *apic = ioapics[best].io_apic;
  544         *pin = intr - ioapics[best].io_vector;
  545         if (*pin > 32)
  546                 printf("WARNING: Found intpin of %u for vector %d\n", *pin,
  547                     intr);
  548         return (0);
  549 }
  550 
  551 void
  552 madt_parse_interrupt_values(void *entry,
  553     enum intr_trigger *trig, enum intr_polarity *pol)
  554 {
  555         ACPI_MADT_INTERRUPT_OVERRIDE *intr;
  556         char buf[64];
  557 
  558         intr = entry;
  559 
  560         if (bootverbose)
  561                 printf("MADT: Interrupt override: source %u, irq %u\n",
  562                     intr->SourceIrq, intr->GlobalIrq);
  563         KASSERT(intr->Bus == 0, ("bus for interrupt overrides must be zero"));
  564 
  565         /*
  566          * Lookup the appropriate trigger and polarity modes for this
  567          * entry.
  568          */
  569         *trig = interrupt_trigger(intr->IntiFlags, intr->SourceIrq);
  570         *pol = interrupt_polarity(intr->IntiFlags, intr->SourceIrq);
  571 
  572         /*
  573          * If the SCI is identity mapped but has edge trigger and
  574          * active-hi polarity or the force_sci_lo tunable is set,
  575          * force it to use level/lo.
  576          */
  577         if (intr->SourceIrq == AcpiGbl_FADT.SciInterrupt) {
  578                 madt_found_sci_override = 1;
  579                 if (getenv_string("hw.acpi.sci.trigger", buf, sizeof(buf))) {
  580                         if (tolower(buf[0]) == 'e')
  581                                 *trig = INTR_TRIGGER_EDGE;
  582                         else if (tolower(buf[0]) == 'l')
  583                                 *trig = INTR_TRIGGER_LEVEL;
  584                         else
  585                                 panic(
  586                                 "Invalid trigger %s: must be 'edge' or 'level'",
  587                                     buf);
  588                         printf("MADT: Forcing SCI to %s trigger\n",
  589                             *trig == INTR_TRIGGER_EDGE ? "edge" : "level");
  590                 }
  591                 if (getenv_string("hw.acpi.sci.polarity", buf, sizeof(buf))) {
  592                         if (tolower(buf[0]) == 'h')
  593                                 *pol = INTR_POLARITY_HIGH;
  594                         else if (tolower(buf[0]) == 'l')
  595                                 *pol = INTR_POLARITY_LOW;
  596                         else
  597                                 panic(
  598                                 "Invalid polarity %s: must be 'high' or 'low'",
  599                                     buf);
  600                         printf("MADT: Forcing SCI to active %s polarity\n",
  601                             *pol == INTR_POLARITY_HIGH ? "high" : "low");
  602                 }
  603         }
  604 }
  605 
  606 /*
  607  * Parse an interrupt source override for an ISA interrupt.
  608  */
  609 static void
  610 madt_parse_interrupt_override(ACPI_MADT_INTERRUPT_OVERRIDE *intr)
  611 {
  612         void *new_ioapic, *old_ioapic;
  613         u_int new_pin, old_pin;
  614         enum intr_trigger trig;
  615         enum intr_polarity pol;
  616 
  617         if (acpi_quirks & ACPI_Q_MADT_IRQ0 && intr->SourceIrq == 0 &&
  618             intr->GlobalIrq == 2) {
  619                 if (bootverbose)
  620                         printf("MADT: Skipping timer override\n");
  621                 return;
  622         }
  623 
  624         if (madt_find_interrupt(intr->GlobalIrq, &new_ioapic, &new_pin) != 0) {
  625                 printf("MADT: Could not find APIC for vector %u (IRQ %u)\n",
  626                     intr->GlobalIrq, intr->SourceIrq);
  627                 return;
  628         }
  629 
  630         madt_parse_interrupt_values(intr, &trig, &pol);
  631 
  632         /* Remap the IRQ if it is mapped to a different interrupt vector. */
  633         if (intr->SourceIrq != intr->GlobalIrq) {
  634                 /*
  635                  * If the SCI is remapped to a non-ISA global interrupt,
  636                  * then override the vector we use to setup and allocate
  637                  * the interrupt.
  638                  */
  639                 if (intr->GlobalIrq > 15 &&
  640                     intr->SourceIrq == AcpiGbl_FADT.SciInterrupt)
  641                         acpi_OverrideInterruptLevel(intr->GlobalIrq);
  642                 else
  643                         ioapic_remap_vector(new_ioapic, new_pin,
  644                             intr->SourceIrq);
  645                 if (madt_find_interrupt(intr->SourceIrq, &old_ioapic,
  646                     &old_pin) != 0)
  647                         printf("MADT: Could not find APIC for source IRQ %u\n",
  648                             intr->SourceIrq);
  649                 else if (ioapic_get_vector(old_ioapic, old_pin) ==
  650                     intr->SourceIrq)
  651                         ioapic_disable_pin(old_ioapic, old_pin);
  652         }
  653 
  654         /* Program the polarity and trigger mode. */
  655         ioapic_set_triggermode(new_ioapic, new_pin, trig);
  656         ioapic_set_polarity(new_ioapic, new_pin, pol);
  657 }
  658 
  659 /*
  660  * Parse an entry for an NMI routed to an IO APIC.
  661  */
  662 static void
  663 madt_parse_nmi(ACPI_MADT_NMI_SOURCE *nmi)
  664 {
  665         void *ioapic;
  666         u_int pin;
  667 
  668         if (madt_find_interrupt(nmi->GlobalIrq, &ioapic, &pin) != 0) {
  669                 printf("MADT: Could not find APIC for vector %u\n",
  670                     nmi->GlobalIrq);
  671                 return;
  672         }
  673 
  674         ioapic_set_nmi(ioapic, pin);
  675         if (!(nmi->IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
  676                 ioapic_set_triggermode(ioapic, pin,
  677                     interrupt_trigger(nmi->IntiFlags, 0));
  678         if (!(nmi->IntiFlags & ACPI_MADT_POLARITY_CONFORMS))
  679                 ioapic_set_polarity(ioapic, pin,
  680                     interrupt_polarity(nmi->IntiFlags, 0));
  681 }
  682 
  683 /*
  684  * Parse an entry for an NMI routed to a local APIC LVT pin.
  685  */
  686 static void
  687 madt_handle_local_nmi(u_int acpi_id, UINT8 Lint, UINT16 IntiFlags)
  688 {
  689         u_int apic_id, pin;
  690 
  691         if (acpi_id == 0xffffffff)
  692                 apic_id = APIC_ID_ALL;
  693         else if (madt_find_cpu(acpi_id, &apic_id) != 0) {
  694                 if (bootverbose)
  695                         printf("MADT: Ignoring local NMI routed to "
  696                             "ACPI CPU %u\n", acpi_id);
  697                 return;
  698         }
  699         if (Lint == 0)
  700                 pin = APIC_LVT_LINT0;
  701         else
  702                 pin = APIC_LVT_LINT1;
  703         lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI);
  704         if (!(IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
  705                 lapic_set_lvt_triggermode(apic_id, pin,
  706                     interrupt_trigger(IntiFlags, 0));
  707         if (!(IntiFlags & ACPI_MADT_POLARITY_CONFORMS))
  708                 lapic_set_lvt_polarity(apic_id, pin,
  709                     interrupt_polarity(IntiFlags, 0));
  710 }
  711 
  712 static void
  713 madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi)
  714 {
  715 
  716         madt_handle_local_nmi(nmi->ProcessorId == 0xff ? 0xffffffff :
  717             nmi->ProcessorId, nmi->Lint, nmi->IntiFlags);
  718 }
  719 
  720 static void
  721 madt_parse_local_x2apic_nmi(ACPI_MADT_LOCAL_X2APIC_NMI *nmi)
  722 {
  723 
  724         madt_handle_local_nmi(nmi->Uid, nmi->Lint, nmi->IntiFlags);
  725 }
  726 
  727 /*
  728  * Parse interrupt entries.
  729  */
  730 static void
  731 madt_parse_ints(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
  732 {
  733 
  734         switch (entry->Type) {
  735         case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
  736                 madt_parse_interrupt_override(
  737                         (ACPI_MADT_INTERRUPT_OVERRIDE *)entry);
  738                 break;
  739         case ACPI_MADT_TYPE_NMI_SOURCE:
  740                 madt_parse_nmi((ACPI_MADT_NMI_SOURCE *)entry);
  741                 break;
  742         case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
  743                 madt_parse_local_nmi((ACPI_MADT_LOCAL_APIC_NMI *)entry);
  744                 break;
  745         case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI:
  746                 madt_parse_local_x2apic_nmi(
  747                     (ACPI_MADT_LOCAL_X2APIC_NMI *)entry);
  748                 break;
  749         }
  750 }
  751 
  752 /*
  753  * Setup per-CPU ACPI IDs.
  754  */
  755 static void
  756 madt_set_ids(void *dummy)
  757 {
  758         struct lapic_info *la;
  759         struct pcpu *pc;
  760         u_int i;
  761 
  762         if (madt == NULL)
  763                 return;
  764 
  765         KASSERT(lapics != NULL, ("local APICs not initialized"));
  766 
  767         CPU_FOREACH(i) {
  768                 pc = pcpu_find(i);
  769                 KASSERT(pc != NULL, ("no pcpu data for CPU %u", i));
  770                 la = &lapics[pc->pc_apic_id];
  771                 if (!la->la_enabled)
  772                         panic("APIC: CPU with APIC ID %u is not enabled",
  773                             pc->pc_apic_id);
  774                 pc->pc_acpi_id = la->la_acpi_id;
  775                 if (bootverbose)
  776                         printf("APIC: CPU %u has ACPI ID %u\n", i,
  777                             la->la_acpi_id);
  778         }
  779 }
  780 SYSINIT(madt_set_ids, SI_SUB_CPU, SI_ORDER_MIDDLE, madt_set_ids, NULL);

Cache object: 4356b36033b47e9dcaf0c48a7899d3d4


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