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/acpi_machdep.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) 2001 Mitsuru IWASAKI
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   26  * SUCH DAMAGE.
   27  */
   28 
   29 #include <sys/cdefs.h>
   30 __FBSDID("$FreeBSD: releng/12.0/sys/i386/acpica/acpi_machdep.c 326260 2017-11-27 15:08:52Z pfg $");
   31 
   32 #include <sys/param.h>
   33 #include <sys/bus.h>
   34 #include <sys/kernel.h>
   35 #include <sys/module.h>
   36 #include <sys/sysctl.h>
   37 
   38 #include <vm/vm.h>
   39 #include <vm/pmap.h>
   40 
   41 #include <contrib/dev/acpica/include/acpi.h>
   42 #include <contrib/dev/acpica/include/accommon.h>
   43 #include <contrib/dev/acpica/include/actables.h>
   44 
   45 #include <dev/acpica/acpivar.h>
   46 
   47 #include <machine/nexusvar.h>
   48 
   49 uint32_t acpi_resume_beep;
   50 SYSCTL_UINT(_debug_acpi, OID_AUTO, resume_beep, CTLFLAG_RWTUN, &acpi_resume_beep,
   51     0, "Beep the PC speaker when resuming");
   52 
   53 uint32_t acpi_reset_video;
   54 TUNABLE_INT("hw.acpi.reset_video", &acpi_reset_video);
   55 
   56 static int intr_model = ACPI_INTR_PIC;
   57 
   58 int
   59 acpi_machdep_init(device_t dev)
   60 {
   61         struct acpi_softc *sc;
   62 
   63         sc = device_get_softc(dev);
   64 
   65         acpi_apm_init(sc);
   66         acpi_install_wakeup_handler(sc);
   67 
   68         if (intr_model == ACPI_INTR_PIC)
   69                 BUS_CONFIG_INTR(dev, AcpiGbl_FADT.SciInterrupt,
   70                     INTR_TRIGGER_LEVEL, INTR_POLARITY_LOW);
   71         else
   72                 acpi_SetIntrModel(intr_model);
   73 
   74         SYSCTL_ADD_UINT(&sc->acpi_sysctl_ctx,
   75             SYSCTL_CHILDREN(sc->acpi_sysctl_tree), OID_AUTO,
   76             "reset_video", CTLFLAG_RW, &acpi_reset_video, 0,
   77             "Call the VESA reset BIOS vector on the resume path");
   78 
   79         return (0);
   80 }
   81 
   82 void
   83 acpi_SetDefaultIntrModel(int model)
   84 {
   85 
   86         intr_model = model;
   87 }
   88 
   89 /* Check BIOS date.  If 1998 or older, disable ACPI. */
   90 int
   91 acpi_machdep_quirks(int *quirks)
   92 {
   93         char *va;
   94         int year;
   95 
   96         /* BIOS address 0xffff5 contains the date in the format mm/dd/yy. */
   97         va = pmap_mapbios(0xffff0, 16);
   98         sscanf(va + 11, "%2d", &year);
   99         pmap_unmapbios((vm_offset_t)va, 16);
  100 
  101         /* 
  102          * Date must be >= 1/1/1999 or we don't trust ACPI.  Note that this
  103          * check must be changed by my 114th birthday.
  104          */
  105         if (year > 90 && year < 99)
  106                 *quirks = ACPI_Q_BROKEN;
  107 
  108         return (0);
  109 }
  110 
  111 /*
  112  * Support for mapping ACPI tables during early boot.  This abuses the
  113  * crashdump map because the kernel cannot allocate KVA in
  114  * pmap_mapbios() when this is used.  This makes the following
  115  * assumptions about how we use this KVA: pages 0 and 1 are used to
  116  * map in the header of each table found via the RSDT or XSDT and
  117  * pages 2 to n are used to map in the RSDT or XSDT.  This has to use
  118  * 2 pages for the table headers in case a header spans a page
  119  * boundary.
  120  *
  121  * XXX: We don't ensure the table fits in the available address space
  122  * in the crashdump map.
  123  */
  124 
  125 /*
  126  * Map some memory using the crashdump map.  'offset' is an offset in
  127  * pages into the crashdump map to use for the start of the mapping.
  128  */
  129 static void *
  130 table_map(vm_paddr_t pa, int offset, vm_offset_t length)
  131 {
  132         vm_offset_t va, off;
  133         void *data;
  134 
  135         off = pa & PAGE_MASK;
  136         length = round_page(length + off);
  137         pa = pa & PG_FRAME;
  138         va = (vm_offset_t)pmap_kenter_temporary(pa, offset) +
  139             (offset * PAGE_SIZE);
  140         data = (void *)(va + off);
  141         length -= PAGE_SIZE;
  142         while (length > 0) {
  143                 va += PAGE_SIZE;
  144                 pa += PAGE_SIZE;
  145                 length -= PAGE_SIZE;
  146                 pmap_kenter(va, pa);
  147                 invlpg(va);
  148         }
  149         return (data);
  150 }
  151 
  152 /* Unmap memory previously mapped with table_map(). */
  153 static void
  154 table_unmap(void *data, vm_offset_t length)
  155 {
  156         vm_offset_t va, off;
  157 
  158         va = (vm_offset_t)data;
  159         off = va & PAGE_MASK;
  160         length = round_page(length + off);
  161         va &= ~PAGE_MASK;
  162         while (length > 0) {
  163                 pmap_kremove(va);
  164                 invlpg(va);
  165                 va += PAGE_SIZE;
  166                 length -= PAGE_SIZE;
  167         }
  168 }
  169 
  170 /*
  171  * Map a table at a given offset into the crashdump map.  It first
  172  * maps the header to determine the table length and then maps the
  173  * entire table.
  174  */
  175 static void *
  176 map_table(vm_paddr_t pa, int offset, const char *sig)
  177 {
  178         ACPI_TABLE_HEADER *header;
  179         vm_offset_t length;
  180         void *table;
  181 
  182         header = table_map(pa, offset, sizeof(ACPI_TABLE_HEADER));
  183         if (strncmp(header->Signature, sig, ACPI_NAME_SIZE) != 0) {
  184                 table_unmap(header, sizeof(ACPI_TABLE_HEADER));
  185                 return (NULL);
  186         }
  187         length = header->Length;
  188         table_unmap(header, sizeof(ACPI_TABLE_HEADER));
  189         table = table_map(pa, offset, length);
  190         if (ACPI_FAILURE(AcpiTbChecksum(table, length))) {
  191                 if (bootverbose)
  192                         printf("ACPI: Failed checksum for table %s\n", sig);
  193 #if (ACPI_CHECKSUM_ABORT)
  194                 table_unmap(table, length);
  195                 return (NULL);
  196 #endif
  197         }
  198         return (table);
  199 }
  200 
  201 /*
  202  * See if a given ACPI table is the requested table.  Returns the
  203  * length of the able if it matches or zero on failure.
  204  */
  205 static int
  206 probe_table(vm_paddr_t address, const char *sig)
  207 {
  208         ACPI_TABLE_HEADER *table;
  209 
  210         table = table_map(address, 0, sizeof(ACPI_TABLE_HEADER));
  211         if (table == NULL) {
  212                 if (bootverbose)
  213                         printf("ACPI: Failed to map table at 0x%jx\n",
  214                             (uintmax_t)address);
  215                 return (0);
  216         }
  217         if (bootverbose)
  218                 printf("Table '%.4s' at 0x%jx\n", table->Signature,
  219                     (uintmax_t)address);
  220 
  221         if (strncmp(table->Signature, sig, ACPI_NAME_SIZE) != 0) {
  222                 table_unmap(table, sizeof(ACPI_TABLE_HEADER));
  223                 return (0);
  224         }
  225         table_unmap(table, sizeof(ACPI_TABLE_HEADER));
  226         return (1);
  227 }
  228 
  229 /*
  230  * Try to map a table at a given physical address previously returned
  231  * by acpi_find_table().
  232  */
  233 void *
  234 acpi_map_table(vm_paddr_t pa, const char *sig)
  235 {
  236 
  237         return (map_table(pa, 0, sig));
  238 }
  239 
  240 /* Unmap a table previously mapped via acpi_map_table(). */
  241 void
  242 acpi_unmap_table(void *table)
  243 {
  244         ACPI_TABLE_HEADER *header;
  245 
  246         header = (ACPI_TABLE_HEADER *)table;
  247         table_unmap(table, header->Length);
  248 }
  249 
  250 /*
  251  * Return the physical address of the requested table or zero if one
  252  * is not found.
  253  */
  254 vm_paddr_t
  255 acpi_find_table(const char *sig)
  256 {
  257         ACPI_PHYSICAL_ADDRESS rsdp_ptr;
  258         ACPI_TABLE_RSDP *rsdp;
  259         ACPI_TABLE_RSDT *rsdt;
  260         ACPI_TABLE_XSDT *xsdt;
  261         ACPI_TABLE_HEADER *table;
  262         vm_paddr_t addr;
  263         int i, count;
  264 
  265         if (resource_disabled("acpi", 0))
  266                 return (0);
  267 
  268         /*
  269          * Map in the RSDP.  Since ACPI uses AcpiOsMapMemory() which in turn
  270          * calls pmap_mapbios() to find the RSDP, we assume that we can use
  271          * pmap_mapbios() to map the RSDP.
  272          */
  273         if ((rsdp_ptr = AcpiOsGetRootPointer()) == 0)
  274                 return (0);
  275         rsdp = pmap_mapbios(rsdp_ptr, sizeof(ACPI_TABLE_RSDP));
  276         if (rsdp == NULL) {
  277                 if (bootverbose)
  278                         printf("ACPI: Failed to map RSDP\n");
  279                 return (0);
  280         }
  281 
  282         /*
  283          * For ACPI >= 2.0, use the XSDT if it is available.
  284          * Otherwise, use the RSDT.  We map the XSDT or RSDT at page 2
  285          * in the crashdump area.  Pages 0 and 1 are used to map in the
  286          * headers of candidate ACPI tables.
  287          */
  288         addr = 0;
  289         if (rsdp->Revision >= 2 && rsdp->XsdtPhysicalAddress != 0) {
  290                 /*
  291                  * AcpiOsGetRootPointer only verifies the checksum for
  292                  * the version 1.0 portion of the RSDP.  Version 2.0 has
  293                  * an additional checksum that we verify first.
  294                  */
  295                 if (AcpiTbChecksum((UINT8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH)) {
  296                         if (bootverbose)
  297                                 printf("ACPI: RSDP failed extended checksum\n");
  298                         return (0);
  299                 }
  300                 xsdt = map_table(rsdp->XsdtPhysicalAddress, 2, ACPI_SIG_XSDT);
  301                 if (xsdt == NULL) {
  302                         if (bootverbose)
  303                                 printf("ACPI: Failed to map XSDT\n");
  304                         return (0);
  305                 }
  306                 count = (xsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
  307                     sizeof(UINT64);
  308                 for (i = 0; i < count; i++)
  309                         if (probe_table(xsdt->TableOffsetEntry[i], sig)) {
  310                                 addr = xsdt->TableOffsetEntry[i];
  311                                 break;
  312                         }
  313                 acpi_unmap_table(xsdt);
  314         } else {
  315                 rsdt = map_table(rsdp->RsdtPhysicalAddress, 2, ACPI_SIG_RSDT);
  316                 if (rsdt == NULL) {
  317                         if (bootverbose)
  318                                 printf("ACPI: Failed to map RSDT\n");
  319                         return (0);
  320                 }
  321                 count = (rsdt->Header.Length - sizeof(ACPI_TABLE_HEADER)) /
  322                     sizeof(UINT32);
  323                 for (i = 0; i < count; i++)
  324                         if (probe_table(rsdt->TableOffsetEntry[i], sig)) {
  325                                 addr = rsdt->TableOffsetEntry[i];
  326                                 break;
  327                         }
  328                 acpi_unmap_table(rsdt);
  329         }
  330         pmap_unmapbios((vm_offset_t)rsdp, sizeof(ACPI_TABLE_RSDP));
  331         if (addr == 0) {
  332                 if (bootverbose)
  333                         printf("ACPI: No %s table found\n", sig);
  334                 return (0);
  335         }
  336         if (bootverbose)
  337                 printf("%s: Found table at 0x%jx\n", sig, (uintmax_t)addr);
  338 
  339         /*
  340          * Verify that we can map the full table and that its checksum is
  341          * correct, etc.
  342          */
  343         table = map_table(addr, 0, sig);
  344         if (table == NULL)
  345                 return (0);
  346         acpi_unmap_table(table);
  347 
  348         return (addr);
  349 }
  350 
  351 /*
  352  * ACPI nexus(4) driver.
  353  */
  354 static int
  355 nexus_acpi_probe(device_t dev)
  356 {
  357         int error;
  358 
  359         error = acpi_identify();
  360         if (error)
  361                 return (error);
  362 
  363         return (BUS_PROBE_DEFAULT);
  364 }
  365 
  366 static int
  367 nexus_acpi_attach(device_t dev)
  368 {
  369 
  370         nexus_init_resources();
  371         bus_generic_probe(dev);
  372         if (BUS_ADD_CHILD(dev, 10, "acpi", 0) == NULL)
  373                 panic("failed to add acpi0 device");
  374 
  375         return (bus_generic_attach(dev));
  376 }
  377 
  378 static device_method_t nexus_acpi_methods[] = {
  379         /* Device interface */
  380         DEVMETHOD(device_probe,         nexus_acpi_probe),
  381         DEVMETHOD(device_attach,        nexus_acpi_attach),
  382 
  383         { 0, 0 }
  384 };
  385 
  386 DEFINE_CLASS_1(nexus, nexus_acpi_driver, nexus_acpi_methods, 1, nexus_driver);
  387 static devclass_t nexus_devclass;
  388 
  389 DRIVER_MODULE(nexus_acpi, root, nexus_acpi_driver, nexus_devclass, 0, 0);

Cache object: 7b46516388d6a836cab16a09c688bc82


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