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/i386/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  * Copyright (c) 2003 John Baldwin <jhb@FreeBSD.org>
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *    notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *    notice, this list of conditions and the following disclaimer in the
   12  *    documentation and/or other materials provided with the distribution.
   13  * 3. Neither the name of the author nor the names of any co-contributors
   14  *    may be used to endorse or promote products derived from this software
   15  *    without specific prior written permission.
   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 <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/bus.h>
   36 #include <sys/kernel.h>
   37 #include <sys/malloc.h>
   38 #include <sys/smp.h>
   39 
   40 #include <vm/vm.h>
   41 #include <vm/vm_param.h>
   42 #include <vm/pmap.h>
   43 
   44 #include <machine/apicreg.h>
   45 #include <machine/frame.h>
   46 #include <machine/intr_machdep.h>
   47 #include <machine/apicvar.h>
   48 #include <machine/md_var.h>
   49 #include <machine/specialreg.h>
   50 
   51 #include <contrib/dev/acpica/acpi.h>
   52 #include <contrib/dev/acpica/actables.h>
   53 #include <dev/acpica/acpivar.h>
   54 #include <dev/pci/pcivar.h>
   55 
   56 typedef void madt_entry_handler(ACPI_SUBTABLE_HEADER *entry, void *arg);
   57 
   58 /* These two arrays are indexed by APIC IDs. */
   59 struct ioapic_info {
   60         void *io_apic;
   61         UINT32 io_vector;
   62 } ioapics[MAX_APIC_ID + 1];
   63 
   64 struct lapic_info {
   65         u_int la_enabled:1;
   66         u_int la_acpi_id:8;
   67 } lapics[MAX_APIC_ID + 1];
   68 
   69 static int madt_found_sci_override;
   70 static ACPI_TABLE_MADT *madt;
   71 static vm_paddr_t madt_physaddr;
   72 static vm_offset_t madt_length;
   73 
   74 MALLOC_DEFINE(M_MADT, "madt_table", "ACPI MADT Table Items");
   75 
   76 static enum intr_polarity interrupt_polarity(UINT16 IntiFlags, UINT8 Source);
   77 static enum intr_trigger interrupt_trigger(UINT16 IntiFlags, UINT8 Source);
   78 static int      madt_find_cpu(u_int acpi_id, u_int *apic_id);
   79 static int      madt_find_interrupt(int intr, void **apic, u_int *pin);
   80 static void     *madt_map(vm_paddr_t pa, int offset, vm_offset_t length);
   81 static void     *madt_map_table(vm_paddr_t pa, int offset, const char *sig);
   82 static void     madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg);
   83 static void     madt_parse_interrupt_override(
   84                     ACPI_MADT_INTERRUPT_OVERRIDE *intr);
   85 static void     madt_parse_ints(ACPI_SUBTABLE_HEADER *entry,
   86                     void *arg __unused);
   87 static void     madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi);
   88 static void     madt_parse_nmi(ACPI_MADT_NMI_SOURCE *nmi);
   89 static int      madt_probe(void);
   90 static int      madt_probe_cpus(void);
   91 static void     madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry,
   92                     void *arg __unused);
   93 static int      madt_probe_table(vm_paddr_t address);
   94 static void     madt_register(void *dummy);
   95 static int      madt_setup_local(void);
   96 static int      madt_setup_io(void);
   97 static void     madt_unmap(void *data, vm_offset_t length);
   98 static void     madt_unmap_table(void *table);
   99 static void     madt_walk_table(madt_entry_handler *handler, void *arg);
  100 
  101 static struct apic_enumerator madt_enumerator = {
  102         "MADT",
  103         madt_probe,
  104         madt_probe_cpus,
  105         madt_setup_local,
  106         madt_setup_io
  107 };
  108 
  109 /*
  110  * Code to abuse the crashdump map to map in the tables for the early
  111  * probe.  We cheat and make the following assumptions about how we
  112  * use this KVA: page 0 is used to map in the first page of each table
  113  * found via the RSDT or XSDT and pages 1 to n are used to map in the
  114  * RSDT or XSDT.  The offset is in pages; the length is in bytes.
  115  */
  116 static void *
  117 madt_map(vm_paddr_t pa, int offset, vm_offset_t length)
  118 {
  119         vm_offset_t va, off;
  120         void *data;
  121 
  122         off = pa & PAGE_MASK;
  123         length = roundup(length + off, PAGE_SIZE);
  124         pa = pa & PG_FRAME;
  125         va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
  126             (offset * PAGE_SIZE);
  127         data = (void *)(va + off);
  128         length -= PAGE_SIZE;
  129         while (length > 0) {
  130                 va += PAGE_SIZE;
  131                 pa += PAGE_SIZE;
  132                 length -= PAGE_SIZE;
  133                 pmap_kenter(va, pa);
  134                 invlpg(va);
  135         }
  136         return (data);
  137 }
  138 
  139 static void
  140 madt_unmap(void *data, vm_offset_t length)
  141 {
  142         vm_offset_t va, off;
  143 
  144         va = (vm_offset_t)data;
  145         off = va & PAGE_MASK;
  146         length = roundup(length + off, PAGE_SIZE);
  147         va &= ~PAGE_MASK;
  148         while (length > 0) {
  149                 pmap_kremove(va);
  150                 invlpg(va);
  151                 va += PAGE_SIZE;
  152                 length -= PAGE_SIZE;
  153         }
  154 }
  155 
  156 static void *
  157 madt_map_table(vm_paddr_t pa, int offset, const char *sig)
  158 {
  159         ACPI_TABLE_HEADER *header;
  160         vm_offset_t length;
  161         void *table;
  162 
  163         header = madt_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
  164         if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
  165                 madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
  166                 return (NULL);
  167         }
  168         length = header->Length;
  169         madt_unmap(header, sizeof(ACPI_TABLE_HEADER));
  170         table = madt_map(pa, offset, length);
  171         if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
  172                 if (bootverbose)
  173                         printf("MADT: Failed checksum for table %s\n", sig);
  174                 madt_unmap(table, length);
  175                 return (NULL);
  176         }
  177         return (table);
  178 }
  179 
  180 static void
  181 madt_unmap_table(void *table)
  182 {
  183         ACPI_TABLE_HEADER *header;
  184 
  185         header = (ACPI_TABLE_HEADER *)table;
  186         madt_unmap(table, header->Length);
  187 }
  188 
  189 /*
  190  * Look for an ACPI Multiple APIC Description Table ("APIC")
  191  */
  192 static int
  193 madt_probe(void)
  194 {
  195         ACPI_PHYSICAL_ADDRESS rsdp_ptr;
  196         ACPI_TABLE_RSDP *rsdp;
  197         ACPI_TABLE_RSDT *rsdt;
  198         ACPI_TABLE_XSDT *xsdt;
  199         int i, count;
  200 
  201         if (resource_disabled("acpi", 0))
  202                 return (ENXIO);
  203 
  204         /*
  205          * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
  206          * calls pmap_mapbios() to find the RSDP, we assume that we can use
  207          * pmap_mapbios() to map the RSDP.
  208          */
  209         if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
  210                 return (ENXIO);
  211         rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
  212         if (rsdp == NULL) {
  213                 if (bootverbose)
  214                         printf("MADT: Failed to map RSDP\n");
  215                 return (ENXIO);
  216         }
  217 
  218         /*
  219          * For ACPI >= 2.0, use the XSDT if it is available.
  220          * Otherwise, use the RSDT.  We map the XSDT or RSDT at page 1
  221          * in the crashdump area.  Page 0 is used to map in the
  222          * headers of candidate ACPI tables.
  223          */
  224         if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
  225                 /*
  226                  * AcpiOsGetRootPointer only verifies the checksum for
  227                  * the version 1.0 portion of the RSDP.  Version 2.0 has
  228                  * an additional checksum that we verify first.
  229                  */
  230                 if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
  231                         if (bootverbose)
  232                                 printf("MADT: RSDP failed extended checksum\n");
  233                         return (ENXIO);
  234                 }
  235                 xsdt = madt_map_table(rsdp->XsdtPhysicalAddress, 1,
  236                     ACPI_SIG_XSDT);
  237                 if (xsdt == NULL) {
  238                         if (bootverbose)
  239                                 printf("MADT: Failed to map XSDT\n");
  240                         return (ENXIO);
  241                 }
  242                 count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
  243                     sizeof(UINT64);
  244                 for (i = 0; i < count; i++)
  245                         if (madt_probe_table(xsdt->TableOffsetEntry[i]))
  246                                 break;
  247                 madt_unmap_table(xsdt);
  248         } else {
  249                 rsdt = madt_map_table(rsdp->RsdtPhysicalAddress, 1,
  250                     ACPI_SIG_RSDT);
  251                 if (rsdt == NULL) {
  252                         if (bootverbose)
  253                                 printf("MADT: Failed to map RSDT\n");
  254                         return (ENXIO);
  255                 }
  256                 count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
  257                     sizeof(UINT32);
  258                 for (i = 0; i < count; i++)
  259                         if (madt_probe_table(rsdt->TableOffsetEntry[i]))
  260                                 break;
  261                 madt_unmap_table(rsdt);
  262         }
  263         pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
  264         if (madt_physaddr == 0) {
  265                 if (bootverbose)
  266                         printf("MADT: No MADT table found\n");
  267                 return (ENXIO);
  268         }
  269         if (bootverbose)
  270                 printf("MADT: Found table at 0x%jx\n",
  271                     (uintmax_t)madt_physaddr);
  272 
  273         /*
  274          * Verify that we can map the full table and that its checksum is
  275          * correct, etc.
  276          */
  277         madt = madt_map_table(madt_physaddr, 0, ACPI_SIG_MADT);
  278         if (madt == NULL)
  279                 return (ENXIO);
  280         madt_unmap_table(madt);
  281         madt = NULL;
  282 
  283         return (0);
  284 }
  285 
  286 /*
  287  * See if a given ACPI table is the MADT.
  288  */
  289 static int
  290 madt_probe_table(vm_paddr_t address)
  291 {
  292         ACPI_TABLE_HEADER *table;
  293 
  294         table = madt_map(address, 0, sizeof(ACPI_TABLE_HEADER));
  295         if (table == NULL) {
  296                 if (bootverbose)
  297                         printf("MADT: Failed to map table at 0x%jx\n",
  298                             (uintmax_t)address);
  299                 return (0);
  300         }
  301         if (bootverbose)
  302                 printf("Table '%.4s' at 0x%jx\n", table->Signature,
  303                     (uintmax_t)address);
  304 
  305         if (strncmp(table->Signature, ACPI_SIG_MADT, ACPI_NAME_SIZE) != 0) {
  306                 madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
  307                 return (0);
  308         }
  309         madt_physaddr = address;
  310         madt_length = table->Length;
  311         madt_unmap(table, sizeof(ACPI_TABLE_HEADER));
  312         return (1);
  313 }
  314 
  315 /*
  316  * Run through the MP table enumerating CPUs.
  317  */
  318 static int
  319 madt_probe_cpus(void)
  320 {
  321 
  322         madt = madt_map_table(madt_physaddr, 0, ACPI_SIG_MADT);
  323         KASSERT(madt != NULL, ("Unable to re-map MADT"));
  324         madt_walk_table(madt_probe_cpus_handler, NULL);
  325         madt_unmap_table(madt);
  326         madt = NULL;
  327         return (0);
  328 }
  329 
  330 /*
  331  * Initialize the local APIC on the BSP.
  332  */
  333 static int
  334 madt_setup_local(void)
  335 {
  336 
  337         madt = pmap_mapbios(madt_physaddr, madt_length);
  338         lapic_init(madt->Address);
  339         printf("ACPI APIC Table: <%.*s %.*s>\n",
  340             (int)sizeof(madt->Header.OemId), madt->Header.OemId,
  341             (int)sizeof(madt->Header.OemTableId), madt->Header.OemTableId);
  342 
  343         /*
  344          * We ignore 64-bit local APIC override entries.  Should we
  345          * perhaps emit a warning here if we find one?
  346          */
  347         return (0);
  348 }
  349 
  350 /*
  351  * Enumerate I/O APICs and setup interrupt sources.
  352  */
  353 static int
  354 madt_setup_io(void)
  355 {
  356         void *ioapic;
  357         u_int pin;
  358         int i;
  359 
  360         /* Try to initialize ACPI so that we can access the FADT. */
  361         i = acpi_Startup();
  362         if (ACPI_FAILURE(i)) {
  363                 printf("MADT: ACPI Startup failed with %s\n",
  364                     AcpiFormatException(i));
  365                 printf("Try disabling either ACPI or apic support.\n");
  366                 panic("Using MADT but ACPI doesn't work");
  367         }
  368                     
  369         /* First, we run through adding I/O APIC's. */
  370         madt_walk_table(madt_parse_apics, NULL);
  371 
  372         /* Second, we run through the table tweaking interrupt sources. */
  373         madt_walk_table(madt_parse_ints, NULL);
  374 
  375         /*
  376          * If there was not an explicit override entry for the SCI,
  377          * force it to use level trigger and active-low polarity.
  378          */
  379         if (!madt_found_sci_override) {
  380                 if (madt_find_interrupt(AcpiGbl_FADT.SciInterrupt, &ioapic,
  381                     &pin) != 0)
  382                         printf("MADT: Could not find APIC for SCI IRQ %u\n",
  383                             AcpiGbl_FADT.SciInterrupt);
  384                 else {
  385                         printf(
  386         "MADT: Forcing active-low polarity and level trigger for SCI\n");
  387                         ioapic_set_polarity(ioapic, pin, INTR_POLARITY_LOW);
  388                         ioapic_set_triggermode(ioapic, pin, INTR_TRIGGER_LEVEL);
  389                 }
  390         }
  391 
  392         /* Third, we register all the I/O APIC's. */
  393         for (i = 0; i <= MAX_APIC_ID; i++)
  394                 if (ioapics[i].io_apic != NULL)
  395                         ioapic_register(ioapics[i].io_apic);
  396 
  397         /* Finally, we throw the switch to enable the I/O APIC's. */
  398         acpi_SetDefaultIntrModel(ACPI_INTR_APIC);
  399 
  400         return (0);
  401 }
  402 
  403 static void
  404 madt_register(void *dummy __unused)
  405 {
  406 
  407         apic_register_enumerator(&madt_enumerator);
  408 }
  409 SYSINIT(madt_register, SI_SUB_CPU - 1, SI_ORDER_SECOND, madt_register, NULL)
  410 
  411 /*
  412  * Call the handler routine for each entry in the MADT table.
  413  */
  414 static void
  415 madt_walk_table(madt_entry_handler *handler, void *arg)
  416 {
  417         ACPI_SUBTABLE_HEADER *entry;
  418         u_char *p, *end;
  419 
  420         end = (u_char *)(madt) + madt->Header.Length;
  421         for (p = (u_char *)(madt + 1); p < end; ) {
  422                 entry = (ACPI_SUBTABLE_HEADER *)p;
  423                 handler(entry, arg);
  424                 p += entry->Length;
  425         }
  426 }
  427 
  428 static void
  429 madt_probe_cpus_handler(ACPI_SUBTABLE_HEADER *entry, void *arg)
  430 {
  431         ACPI_MADT_LOCAL_APIC *proc;
  432         struct lapic_info *la;
  433 
  434         switch (entry->Type) {
  435         case ACPI_MADT_TYPE_LOCAL_APIC:
  436                 /*
  437                  * The MADT does not include a BSP flag, so we have to
  438                  * let the MP code figure out which CPU is the BSP on
  439                  * its own.
  440                  */
  441                 proc = (ACPI_MADT_LOCAL_APIC *)entry;
  442                 if (bootverbose)
  443                         printf("MADT: Found CPU APIC ID %u ACPI ID %u: %s\n",
  444                             proc->Id, proc->ProcessorId,
  445                             (proc->LapicFlags & ACPI_MADT_ENABLED) ?
  446                             "enabled" : "disabled");
  447                 if (!(proc->LapicFlags & ACPI_MADT_ENABLED))
  448                         break;
  449                 if (proc->Id > MAX_APIC_ID)
  450                         panic("%s: CPU ID %u too high", __func__, proc->Id);
  451                 la = &lapics[proc->Id];
  452                 KASSERT(la->la_enabled == 0,
  453                     ("Duplicate local APIC ID %u", proc->Id));
  454                 la->la_enabled = 1;
  455                 la->la_acpi_id = proc->ProcessorId;
  456                 lapic_create(proc->Id, 0);
  457                 break;
  458         }
  459 }
  460 
  461 
  462 /*
  463  * Add an I/O APIC from an entry in the table.
  464  */
  465 static void
  466 madt_parse_apics(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
  467 {
  468         ACPI_MADT_IO_APIC *apic;
  469 
  470         switch (entry->Type) {
  471         case ACPI_MADT_TYPE_IO_APIC:
  472                 apic = (ACPI_MADT_IO_APIC *)entry;
  473                 if (bootverbose)
  474                         printf(
  475                             "MADT: Found IO APIC ID %u, Interrupt %u at %p\n",
  476                             apic->Id, apic->GlobalIrqBase,
  477                             (void *)(uintptr_t)apic->Address);
  478                 if (apic->Id > MAX_APIC_ID)
  479                         panic("%s: I/O APIC ID %u too high", __func__,
  480                             apic->Id);
  481                 if (ioapics[apic->Id].io_apic != NULL)
  482                         panic("%s: Double APIC ID %u", __func__, apic->Id);
  483                 ioapics[apic->Id].io_apic = ioapic_create(apic->Address,
  484                     apic->Id, apic->GlobalIrqBase);
  485                 ioapics[apic->Id].io_vector = apic->GlobalIrqBase;
  486                 break;
  487         default:
  488                 break;
  489         }
  490 }
  491 
  492 /*
  493  * Determine properties of an interrupt source.  Note that for ACPI these
  494  * functions are only used for ISA interrupts, so we assume ISA bus values
  495  * (Active Hi, Edge Triggered) for conforming values except for the ACPI
  496  * SCI for which we use Active Lo, Level Triggered.
  497  */
  498 static enum intr_polarity
  499 interrupt_polarity(UINT16 IntiFlags, UINT8 Source)
  500 {
  501 
  502         switch (IntiFlags & ACPI_MADT_POLARITY_MASK) {
  503         case ACPI_MADT_POLARITY_CONFORMS:
  504                 if (Source == AcpiGbl_FADT.SciInterrupt)
  505                         return (INTR_POLARITY_LOW);
  506                 else
  507                         return (INTR_POLARITY_HIGH);
  508         case ACPI_MADT_POLARITY_ACTIVE_HIGH:
  509                 return (INTR_POLARITY_HIGH);
  510         case ACPI_MADT_POLARITY_ACTIVE_LOW:
  511                 return (INTR_POLARITY_LOW);
  512         default:
  513                 panic("Bogus Interrupt Polarity");
  514         }
  515 }
  516 
  517 static enum intr_trigger
  518 interrupt_trigger(UINT16 IntiFlags, UINT8 Source)
  519 {
  520 
  521         switch (IntiFlags & ACPI_MADT_TRIGGER_MASK) {
  522         case ACPI_MADT_TRIGGER_CONFORMS:
  523                 if (Source == AcpiGbl_FADT.SciInterrupt)
  524                         return (INTR_TRIGGER_LEVEL);
  525                 else
  526                         return (INTR_TRIGGER_EDGE);
  527         case ACPI_MADT_TRIGGER_EDGE:
  528                 return (INTR_TRIGGER_EDGE);
  529         case ACPI_MADT_TRIGGER_LEVEL:
  530                 return (INTR_TRIGGER_LEVEL);
  531         default:
  532                 panic("Bogus Interrupt Trigger Mode");
  533         }
  534 }
  535 
  536 /*
  537  * Find the local APIC ID associated with a given ACPI Processor ID.
  538  */
  539 static int
  540 madt_find_cpu(u_int acpi_id, u_int *apic_id)
  541 {
  542         int i;
  543 
  544         for (i = 0; i <= MAX_APIC_ID; i++) {
  545                 if (!lapics[i].la_enabled)
  546                         continue;
  547                 if (lapics[i].la_acpi_id != acpi_id)
  548                         continue;
  549                 *apic_id = i;
  550                 return (0);
  551         }
  552         return (ENOENT);
  553 }
  554 
  555 /*
  556  * Find the IO APIC and pin on that APIC associated with a given global
  557  * interrupt.
  558  */
  559 static int
  560 madt_find_interrupt(int intr, void **apic, u_int *pin)
  561 {
  562         int i, best;
  563 
  564         best = -1;
  565         for (i = 0; i <= MAX_APIC_ID; i++) {
  566                 if (ioapics[i].io_apic == NULL ||
  567                     ioapics[i].io_vector > intr)
  568                         continue;
  569                 if (best == -1 ||
  570                     ioapics[best].io_vector < ioapics[i].io_vector)
  571                         best = i;
  572         }
  573         if (best == -1)
  574                 return (ENOENT);
  575         *apic = ioapics[best].io_apic;
  576         *pin = intr - ioapics[best].io_vector;
  577         if (*pin > 32)
  578                 printf("WARNING: Found intpin of %u for vector %d\n", *pin,
  579                     intr);
  580         return (0);
  581 }
  582 
  583 /*
  584  * Parse an interrupt source override for an ISA interrupt.
  585  */
  586 static void
  587 madt_parse_interrupt_override(ACPI_MADT_INTERRUPT_OVERRIDE *intr)
  588 {
  589         void *new_ioapic, *old_ioapic;
  590         u_int new_pin, old_pin;
  591         enum intr_trigger trig;
  592         enum intr_polarity pol;
  593         char buf[64];
  594 
  595         if (acpi_quirks & ACPI_Q_MADT_IRQ0 && intr->SourceIrq == 0 &&
  596             intr->GlobalIrq == 2) {
  597                 if (bootverbose)
  598                         printf("MADT: Skipping timer override\n");
  599                 return;
  600         }
  601         if (bootverbose)
  602                 printf("MADT: Interrupt override: source %u, irq %u\n",
  603                     intr->SourceIrq, intr->GlobalIrq);
  604         KASSERT(intr->Bus == 0, ("bus for interrupt overrides must be zero"));
  605         if (madt_find_interrupt(intr->GlobalIrq, &new_ioapic, &new_pin) != 0) {
  606                 printf("MADT: Could not find APIC for vector %u (IRQ %u)\n",
  607                     intr->GlobalIrq, intr->SourceIrq);
  608                 return;
  609         }
  610 
  611         /*
  612          * Lookup the appropriate trigger and polarity modes for this
  613          * entry.
  614          */
  615         trig = interrupt_trigger(intr->IntiFlags, intr->SourceIrq);
  616         pol = interrupt_polarity(intr->IntiFlags, intr->SourceIrq);
  617         
  618         /*
  619          * If the SCI is identity mapped but has edge trigger and
  620          * active-hi polarity or the force_sci_lo tunable is set,
  621          * force it to use level/lo.
  622          */
  623         if (intr->SourceIrq == AcpiGbl_FADT.SciInterrupt) {
  624                 madt_found_sci_override = 1;
  625                 if (getenv_string("hw.acpi.sci.trigger", buf, sizeof(buf))) {
  626                         if (tolower(buf[0]) == 'e')
  627                                 trig = INTR_TRIGGER_EDGE;
  628                         else if (tolower(buf[0]) == 'l')
  629                                 trig = INTR_TRIGGER_LEVEL;
  630                         else
  631                                 panic(
  632                                 "Invalid trigger %s: must be 'edge' or 'level'",
  633                                     buf);
  634                         printf("MADT: Forcing SCI to %s trigger\n",
  635                             trig == INTR_TRIGGER_EDGE ? "edge" : "level");
  636                 }
  637                 if (getenv_string("hw.acpi.sci.polarity", buf, sizeof(buf))) {
  638                         if (tolower(buf[0]) == 'h')
  639                                 pol = INTR_POLARITY_HIGH;
  640                         else if (tolower(buf[0]) == 'l')
  641                                 pol = INTR_POLARITY_LOW;
  642                         else
  643                                 panic(
  644                                 "Invalid polarity %s: must be 'high' or 'low'",
  645                                     buf);
  646                         printf("MADT: Forcing SCI to active %s polarity\n",
  647                             pol == INTR_POLARITY_HIGH ? "high" : "low");
  648                 }
  649         }
  650 
  651         /* Remap the IRQ if it is mapped to a different interrupt vector. */
  652         if (intr->SourceIrq != intr->GlobalIrq) {
  653                 /*
  654                  * If the SCI is remapped to a non-ISA global interrupt,
  655                  * then override the vector we use to setup and allocate
  656                  * the interrupt.
  657                  */
  658                 if (intr->GlobalIrq > 15 &&
  659                     intr->SourceIrq == AcpiGbl_FADT.SciInterrupt)
  660                         acpi_OverrideInterruptLevel(intr->GlobalIrq);
  661                 else
  662                         ioapic_remap_vector(new_ioapic, new_pin,
  663                             intr->SourceIrq);
  664                 if (madt_find_interrupt(intr->SourceIrq, &old_ioapic,
  665                     &old_pin) != 0)
  666                         printf("MADT: Could not find APIC for source IRQ %u\n",
  667                             intr->SourceIrq);
  668                 else if (ioapic_get_vector(old_ioapic, old_pin) ==
  669                     intr->SourceIrq)
  670                         ioapic_disable_pin(old_ioapic, old_pin);
  671         }
  672 
  673         /* Program the polarity and trigger mode. */
  674         ioapic_set_triggermode(new_ioapic, new_pin, trig);
  675         ioapic_set_polarity(new_ioapic, new_pin, pol);
  676 }
  677 
  678 /*
  679  * Parse an entry for an NMI routed to an IO APIC.
  680  */
  681 static void
  682 madt_parse_nmi(ACPI_MADT_NMI_SOURCE *nmi)
  683 {
  684         void *ioapic;
  685         u_int pin;
  686 
  687         if (madt_find_interrupt(nmi->GlobalIrq, &ioapic, &pin) != 0) {
  688                 printf("MADT: Could not find APIC for vector %u\n",
  689                     nmi->GlobalIrq);
  690                 return;
  691         }
  692 
  693         ioapic_set_nmi(ioapic, pin);
  694         if (!(nmi->IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
  695                 ioapic_set_triggermode(ioapic, pin,
  696                     interrupt_trigger(nmi->IntiFlags, 0));
  697         if (!(nmi->IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
  698                 ioapic_set_polarity(ioapic, pin,
  699                     interrupt_polarity(nmi->IntiFlags, 0));
  700 }
  701 
  702 /*
  703  * Parse an entry for an NMI routed to a local APIC LVT pin.
  704  */
  705 static void
  706 madt_parse_local_nmi(ACPI_MADT_LOCAL_APIC_NMI *nmi)
  707 {
  708         u_int apic_id, pin;
  709 
  710         if (nmi->ProcessorId == 0xff)
  711                 apic_id = APIC_ID_ALL;
  712         else if (madt_find_cpu(nmi->ProcessorId, &apic_id) != 0) {
  713                 if (bootverbose)
  714                         printf("MADT: Ignoring local NMI routed to "
  715                             "ACPI CPU %u\n", nmi->ProcessorId);
  716                 return;
  717         }
  718         if (nmi->Lint == 0)
  719                 pin = LVT_LINT0;
  720         else
  721                 pin = LVT_LINT1;
  722         lapic_set_lvt_mode(apic_id, pin, APIC_LVT_DM_NMI);
  723         if (!(nmi->IntiFlags & ACPI_MADT_TRIGGER_CONFORMS))
  724                 lapic_set_lvt_triggermode(apic_id, pin,
  725                     interrupt_trigger(nmi->IntiFlags, 0));
  726         if (!(nmi->IntiFlags & ACPI_MADT_POLARITY_CONFORMS))
  727                 lapic_set_lvt_polarity(apic_id, pin,
  728                     interrupt_polarity(nmi->IntiFlags, 0));
  729 }
  730 
  731 /*
  732  * Parse interrupt entries.
  733  */
  734 static void
  735 madt_parse_ints(ACPI_SUBTABLE_HEADER *entry, void *arg __unused)
  736 {
  737 
  738         switch (entry->Type) {
  739         case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE:
  740                 madt_parse_interrupt_override(
  741                         (ACPI_MADT_INTERRUPT_OVERRIDE *)entry);
  742                 break;
  743         case ACPI_MADT_TYPE_NMI_SOURCE:
  744                 madt_parse_nmi((ACPI_MADT_NMI_SOURCE *)entry);
  745                 break;
  746         case ACPI_MADT_TYPE_LOCAL_APIC_NMI:
  747                 madt_parse_local_nmi((ACPI_MADT_LOCAL_APIC_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         for (i = 0; i <= mp_maxid; i++) {
  765                 if (CPU_ABSENT(i))
  766                         continue;
  767                 pc = pcpu_find(i);
  768                 KASSERT(pc != NULL, ("no pcpu data for CPU %u", i));
  769                 la = &lapics[pc->pc_apic_id];
  770                 if (!la->la_enabled)
  771                         panic("APIC: CPU with APIC ID %u is not enabled",
  772                             pc->pc_apic_id);
  773                 pc->pc_acpi_id = la->la_acpi_id;
  774                 if (bootverbose)
  775                         printf("APIC: CPU %u has ACPI ID %u\n", i,
  776                             la->la_acpi_id);
  777         }
  778 }
  779 SYSINIT(madt_set_ids, SI_SUB_CPU, SI_ORDER_ANY, madt_set_ids, NULL)

Cache object: 99b79c1ffb5c44e5c88908f70fa36ccd


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