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_apei.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) 2020 Alexander Motin <mav@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 "opt_acpi.h"
   32 #include "opt_pci.h"
   33 
   34 #include <sys/param.h>
   35 #include <sys/systm.h>
   36 #include <sys/bus.h>
   37 #include <sys/callout.h>
   38 #include <sys/interrupt.h>
   39 #include <sys/kernel.h>
   40 #include <sys/malloc.h>
   41 #include <sys/module.h>
   42 #include <sys/queue.h>
   43 #include <sys/rman.h>
   44 #include <vm/vm.h>
   45 #include <vm/pmap.h>
   46 
   47 #include <contrib/dev/acpica/include/acpi.h>
   48 #include <contrib/dev/acpica/include/accommon.h>
   49 #include <contrib/dev/acpica/include/aclocal.h>
   50 #include <contrib/dev/acpica/include/actables.h>
   51 
   52 #include <dev/acpica/acpivar.h>
   53 #include <dev/pci/pcireg.h>
   54 #include <dev/pci/pcivar.h>
   55 
   56 struct apei_ge {
   57         union {
   58                 ACPI_HEST_GENERIC v1;
   59                 ACPI_HEST_GENERIC_V2 v2;
   60         };
   61         int              res_type;
   62         int              res_rid;
   63         struct resource *res;
   64         int              res2_type;
   65         int              res2_rid;
   66         struct resource *res2;
   67         uint8_t         *buf, *copybuf;
   68         TAILQ_ENTRY(apei_ge) link;
   69         TAILQ_ENTRY(apei_ge) nlink;
   70 };
   71 
   72 /* NMI */
   73 struct apei_nges {
   74         void            *swi_ih;
   75         TAILQ_HEAD(, apei_ge) ges;
   76 } *apei_nmi_nges;
   77 
   78 /* Interrupt */
   79 struct apei_iges {
   80         TAILQ_HEAD(, apei_ge) ges;
   81 };
   82 
   83 /* Polling */
   84 struct apei_pges {
   85         sbintime_t       interval;
   86         struct callout   poll;
   87         TAILQ_HEAD(, apei_ge) ges;
   88 };
   89 
   90 struct apei_softc {
   91         ACPI_TABLE_HEST *hest;
   92         TAILQ_HEAD(, apei_ge) ges;
   93         struct apei_nges nges;
   94         struct apei_iges iges;
   95         struct apei_pges pges[32];
   96 };
   97 
   98 struct apei_mem_error {
   99         uint64_t        ValidationBits;
  100         uint64_t        ErrorStatus;
  101         uint64_t        PhysicalAddress;
  102         uint64_t        PhysicalAddressMask;
  103         uint16_t        Node;
  104         uint16_t        Card;
  105         uint16_t        Module;
  106         uint16_t        Bank;
  107         uint16_t        Device;
  108         uint16_t        Row;
  109         uint16_t        Column;
  110         uint16_t        BitPosition;
  111         uint64_t        RequesterID;
  112         uint64_t        ResponderID;
  113         uint64_t        TargetID;
  114         uint8_t         MemoryErrorType;
  115         uint8_t         Extended;
  116         uint16_t        RankNumber;
  117         uint16_t        CardHandle;
  118         uint16_t        ModuleHandle;
  119 };
  120 
  121 struct apei_pcie_error {
  122         uint64_t        ValidationBits;
  123         uint32_t        PortType;
  124         uint32_t        Version;
  125         uint32_t        CommandStatus;
  126         uint32_t        Reserved;
  127         uint8_t         DeviceID[16];
  128         uint8_t         DeviceSerialNumber[8];
  129         uint8_t         BridgeControlStatus[4];
  130         uint8_t         CapabilityStructure[60];
  131         uint8_t         AERInfo[96];
  132 };
  133 
  134 #ifdef __i386__
  135 static __inline uint64_t
  136 apei_bus_read_8(struct resource *res, bus_size_t offset)
  137 {
  138         return (bus_read_4(res, offset) |
  139             ((uint64_t)bus_read_4(res, offset + 4)) << 32);
  140 }
  141 static __inline void
  142 apei_bus_write_8(struct resource *res, bus_size_t offset, uint64_t val)
  143 {
  144         bus_write_4(res, offset, val);
  145         bus_write_4(res, offset + 4, val >> 32);
  146 }
  147 #define READ8(r, o)     apei_bus_read_8((r), (o))
  148 #define WRITE8(r, o, v) apei_bus_write_8((r), (o), (v))
  149 #else
  150 #define READ8(r, o)     bus_read_8((r), (o))
  151 #define WRITE8(r, o, v) bus_write_8((r), (o), (v))
  152 #endif
  153 
  154 #define GED_SIZE(ged)   ((ged)->Revision >= 0x300 ? \
  155     sizeof(ACPI_HEST_GENERIC_DATA_V300) : sizeof(ACPI_HEST_GENERIC_DATA))
  156 #define GED_DATA(ged)   ((uint8_t *)(ged) + GED_SIZE(ged))
  157 
  158 #define PGE_ID(ge)      (fls(MAX(1, (ge)->v1.Notify.PollInterval)) - 1)
  159 
  160 int apei_nmi_handler(void);
  161 
  162 static const char *
  163 apei_severity(uint32_t s)
  164 {
  165         switch (s) {
  166         case ACPI_HEST_GEN_ERROR_RECOVERABLE:
  167             return ("Recoverable");
  168         case ACPI_HEST_GEN_ERROR_FATAL:
  169             return ("Fatal");
  170         case ACPI_HEST_GEN_ERROR_CORRECTED:
  171             return ("Corrected");
  172         case ACPI_HEST_GEN_ERROR_NONE:
  173             return ("Informational");
  174         }
  175         return ("???");
  176 }
  177 
  178 static int
  179 apei_mem_handler(ACPI_HEST_GENERIC_DATA *ged)
  180 {
  181         struct apei_mem_error *p = (struct apei_mem_error *)GED_DATA(ged);
  182 
  183         printf("APEI %s Memory Error:\n", apei_severity(ged->ErrorSeverity));
  184         if (p->ValidationBits & 0x01)
  185                 printf(" Error Status: 0x%jx\n", p->ErrorStatus);
  186         if (p->ValidationBits & 0x02)
  187                 printf(" Physical Address: 0x%jx\n", p->PhysicalAddress);
  188         if (p->ValidationBits & 0x04)
  189                 printf(" Physical Address Mask: 0x%jx\n", p->PhysicalAddressMask);
  190         if (p->ValidationBits & 0x08)
  191                 printf(" Node: %u\n", p->Node);
  192         if (p->ValidationBits & 0x10)
  193                 printf(" Card: %u\n", p->Card);
  194         if (p->ValidationBits & 0x20)
  195                 printf(" Module: %u\n", p->Module);
  196         if (p->ValidationBits & 0x40)
  197                 printf(" Bank: %u\n", p->Bank);
  198         if (p->ValidationBits & 0x80)
  199                 printf(" Device: %u\n", p->Device);
  200         if (p->ValidationBits & 0x100)
  201                 printf(" Row: %u\n", p->Row);
  202         if (p->ValidationBits & 0x200)
  203                 printf(" Column: %u\n", p->Column);
  204         if (p->ValidationBits & 0x400)
  205                 printf(" Bit Position: %u\n", p->BitPosition);
  206         if (p->ValidationBits & 0x800)
  207                 printf(" Requester ID: 0x%jx\n", p->RequesterID);
  208         if (p->ValidationBits & 0x1000)
  209                 printf(" Responder ID: 0x%jx\n", p->ResponderID);
  210         if (p->ValidationBits & 0x2000)
  211                 printf(" Target ID: 0x%jx\n", p->TargetID);
  212         if (p->ValidationBits & 0x4000)
  213                 printf(" Memory Error Type: %u\n", p->MemoryErrorType);
  214         if (p->ValidationBits & 0x8000)
  215                 printf(" Rank Number: %u\n", p->RankNumber);
  216         if (p->ValidationBits & 0x10000)
  217                 printf(" Card Handle: 0x%x\n", p->CardHandle);
  218         if (p->ValidationBits & 0x20000)
  219                 printf(" Module Handle: 0x%x\n", p->ModuleHandle);
  220         if (p->ValidationBits & 0x40000)
  221                 printf(" Extended Row: %u\n",
  222                     (uint32_t)(p->Extended & 0x3) << 16 | p->Row);
  223         if (p->ValidationBits & 0x80000)
  224                 printf(" Bank Group: %u\n", p->Bank >> 8);
  225         if (p->ValidationBits & 0x100000)
  226                 printf(" Bank Address: %u\n", p->Bank & 0xff);
  227         if (p->ValidationBits & 0x200000)
  228                 printf(" Chip Identification: %u\n", (p->Extended >> 5) & 0x7);
  229 
  230         return (0);
  231 }
  232 
  233 static int
  234 apei_pcie_handler(ACPI_HEST_GENERIC_DATA *ged)
  235 {
  236         struct apei_pcie_error *p = (struct apei_pcie_error *)GED_DATA(ged);
  237         int h = 0, off;
  238 #ifdef DEV_PCI
  239         device_t dev;
  240         int sev;
  241 
  242         if ((p->ValidationBits & 0x8) == 0x8) {
  243                 mtx_lock(&Giant);
  244                 dev = pci_find_dbsf((uint32_t)p->DeviceID[10] << 8 |
  245                     p->DeviceID[9], p->DeviceID[11], p->DeviceID[8],
  246                     p->DeviceID[7]);
  247                 if (dev != NULL) {
  248                         switch (ged->ErrorSeverity) {
  249                         case ACPI_HEST_GEN_ERROR_FATAL:
  250                                 sev = PCIEM_STA_FATAL_ERROR;
  251                                 break;
  252                         case ACPI_HEST_GEN_ERROR_RECOVERABLE:
  253                                 sev = PCIEM_STA_NON_FATAL_ERROR;
  254                                 break;
  255                         default:
  256                                 sev = PCIEM_STA_CORRECTABLE_ERROR;
  257                                 break;
  258                         }
  259                         pcie_apei_error(dev, sev,
  260                             (p->ValidationBits & 0x80) ? p->AERInfo : NULL);
  261                         h = 1;
  262                 }
  263                 mtx_unlock(&Giant);
  264         }
  265         if (h)
  266                 return (h);
  267 #endif
  268 
  269         printf("APEI %s PCIe Error:\n", apei_severity(ged->ErrorSeverity));
  270         if (p->ValidationBits & 0x01)
  271                 printf(" Port Type: %u\n", p->PortType);
  272         if (p->ValidationBits & 0x02)
  273                 printf(" Version: %x\n", p->Version);
  274         if (p->ValidationBits & 0x04)
  275                 printf(" Command Status: 0x%08x\n", p->CommandStatus);
  276         if (p->ValidationBits & 0x08) {
  277                 printf(" DeviceID:");
  278                 for (off = 0; off < sizeof(p->DeviceID); off++)
  279                         printf(" %02x", p->DeviceID[off]);
  280                 printf("\n");
  281         }
  282         if (p->ValidationBits & 0x10) {
  283                 printf(" Device Serial Number:");
  284                 for (off = 0; off < sizeof(p->DeviceSerialNumber); off++)
  285                         printf(" %02x", p->DeviceSerialNumber[off]);
  286                 printf("\n");
  287         }
  288         if (p->ValidationBits & 0x20) {
  289                 printf(" Bridge Control Status:");
  290                 for (off = 0; off < sizeof(p->BridgeControlStatus); off++)
  291                         printf(" %02x", p->BridgeControlStatus[off]);
  292                 printf("\n");
  293         }
  294         if (p->ValidationBits & 0x40) {
  295                 printf(" Capability Structure:\n");
  296                 for (off = 0; off < sizeof(p->CapabilityStructure); off++) {
  297                         printf(" %02x", p->CapabilityStructure[off]);
  298                         if ((off % 16) == 15 ||
  299                             off + 1 == sizeof(p->CapabilityStructure))
  300                                 printf("\n");
  301                 }
  302         }
  303         if (p->ValidationBits & 0x80) {
  304                 printf(" AER Info:\n");
  305                 for (off = 0; off < sizeof(p->AERInfo); off++) {
  306                         printf(" %02x", p->AERInfo[off]);
  307                         if ((off % 16) == 15 || off + 1 == sizeof(p->AERInfo))
  308                                 printf("\n");
  309                 }
  310         }
  311         return (h);
  312 }
  313 
  314 static void
  315 apei_ged_handler(ACPI_HEST_GENERIC_DATA *ged)
  316 {
  317         ACPI_HEST_GENERIC_DATA_V300 *ged3 = (ACPI_HEST_GENERIC_DATA_V300 *)ged;
  318         /* A5BC1114-6F64-4EDE-B863-3E83ED7C83B1 */
  319         static uint8_t mem_uuid[ACPI_UUID_LENGTH] = {
  320                 0x14, 0x11, 0xBC, 0xA5, 0x64, 0x6F, 0xDE, 0x4E,
  321                 0xB8, 0x63, 0x3E, 0x83, 0xED, 0x7C, 0x83, 0xB1
  322         };
  323         /* D995E954-BBC1-430F-AD91-B44DCB3C6F35 */
  324         static uint8_t pcie_uuid[ACPI_UUID_LENGTH] = {
  325                 0x54, 0xE9, 0x95, 0xD9, 0xC1, 0xBB, 0x0F, 0x43,
  326                 0xAD, 0x91, 0xB4, 0x4D, 0xCB, 0x3C, 0x6F, 0x35
  327         };
  328         uint8_t *t;
  329         int h = 0, off;
  330 
  331         if (memcmp(mem_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) {
  332                 h = apei_mem_handler(ged);
  333         } else if (memcmp(pcie_uuid, ged->SectionType, ACPI_UUID_LENGTH) == 0) {
  334                 h = apei_pcie_handler(ged);
  335         } else {
  336                 t = ged->SectionType;
  337                 printf("APEI %s Error %02x%02x%02x%02x-%02x%02x-"
  338                     "%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x:\n",
  339                     apei_severity(ged->ErrorSeverity),
  340                     t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6],
  341                     t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
  342                 printf(" Error Data:\n");
  343                 t = (uint8_t *)GED_DATA(ged);
  344                 for (off = 0; off < ged->ErrorDataLength; off++) {
  345                         printf(" %02x", t[off]);
  346                         if ((off % 16) == 15 || off + 1 == ged->ErrorDataLength)
  347                                 printf("\n");
  348                 }
  349         }
  350         if (h)
  351                 return;
  352 
  353         printf(" Flags: 0x%x\n", ged->Flags);
  354         if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_ID) {
  355                 t = ged->FruId;
  356                 printf(" FRU Id: %02x%02x%02x%02x-%02x%02x-%02x%02x-"
  357                     "%02x%02x-%02x%02x%02x%02x%02x%02x\n",
  358                     t[3], t[2], t[1], t[0], t[5], t[4], t[7], t[6],
  359                     t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]);
  360         }
  361         if (ged->ValidationBits & ACPI_HEST_GEN_VALID_FRU_STRING)
  362                 printf(" FRU Text: %.20s\n", ged->FruText);
  363         if (ged->Revision >= 0x300 &&
  364             ged->ValidationBits & ACPI_HEST_GEN_VALID_TIMESTAMP)
  365                 printf(" Timestamp: %016jx\n", ged3->TimeStamp);
  366 }
  367 
  368 static int
  369 apei_ge_handler(struct apei_ge *ge, bool copy)
  370 {
  371         uint8_t *buf = copy ? ge->copybuf : ge->buf;
  372         ACPI_HEST_GENERIC_STATUS *ges = (ACPI_HEST_GENERIC_STATUS *)buf;
  373         ACPI_HEST_GENERIC_DATA *ged;
  374         size_t off, len;
  375         uint32_t sev;
  376         int i, c;
  377 
  378         if (ges == NULL || ges->BlockStatus == 0)
  379                 return (0);
  380 
  381         c = (ges->BlockStatus >> 4) & 0x3ff;
  382         sev = ges->ErrorSeverity;
  383 
  384         /* Process error entries. */
  385         len = MIN(ge->v1.ErrorBlockLength - sizeof(*ges), ges->DataLength);
  386         for (off = i = 0; i < c && off + sizeof(*ged) <= len; i++) {
  387                 ged = (ACPI_HEST_GENERIC_DATA *)&buf[sizeof(*ges) + off];
  388                 if ((uint64_t)GED_SIZE(ged) + ged->ErrorDataLength > len - off)
  389                         break;
  390                 apei_ged_handler(ged);
  391                 off += GED_SIZE(ged) + ged->ErrorDataLength;
  392         }
  393 
  394         /* Acknowledge the error has been processed. */
  395         ges->BlockStatus = 0;
  396         if (!copy && ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2 &&
  397             ge->res2) {
  398                 uint64_t val = READ8(ge->res2, 0);
  399                 val &= ge->v2.ReadAckPreserve;
  400                 val |= ge->v2.ReadAckWrite;
  401                 WRITE8(ge->res2, 0, val);
  402         }
  403 
  404         /* If ACPI told the error is fatal -- make it so. */
  405         if (sev == ACPI_HEST_GEN_ERROR_FATAL)
  406                 panic("APEI Fatal Hardware Error!");
  407 
  408         return (1);
  409 }
  410 
  411 static void
  412 apei_nmi_swi(void *arg)
  413 {
  414         struct apei_nges *nges = arg;
  415         struct apei_ge *ge;
  416 
  417         TAILQ_FOREACH(ge, &nges->ges, nlink)
  418                 apei_ge_handler(ge, true);
  419 }
  420 
  421 int
  422 apei_nmi_handler(void)
  423 {
  424         struct apei_nges *nges = apei_nmi_nges;
  425         struct apei_ge *ge;
  426         ACPI_HEST_GENERIC_STATUS *ges, *gesc;
  427         int handled = 0;
  428 
  429         if (nges == NULL)
  430                 return (0);
  431 
  432         TAILQ_FOREACH(ge, &nges->ges, nlink) {
  433                 ges = (ACPI_HEST_GENERIC_STATUS *)ge->buf;
  434                 if (ges == NULL || ges->BlockStatus == 0)
  435                         continue;
  436 
  437                 /* If ACPI told the error is fatal -- make it so. */
  438                 if (ges->ErrorSeverity == ACPI_HEST_GEN_ERROR_FATAL)
  439                         panic("APEI Fatal Hardware Error!");
  440 
  441                 /* Copy the buffer for later processing. */
  442                 gesc = (ACPI_HEST_GENERIC_STATUS *)ge->copybuf;
  443                 if (gesc->BlockStatus == 0)
  444                         memcpy(ge->copybuf, ge->buf, ge->v1.ErrorBlockLength);
  445 
  446                 /* Acknowledge the error has been processed. */
  447                 ges->BlockStatus = 0;
  448                 if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2 &&
  449                     ge->res2) {
  450                         uint64_t val = READ8(ge->res2, 0);
  451                         val &= ge->v2.ReadAckPreserve;
  452                         val |= ge->v2.ReadAckWrite;
  453                         WRITE8(ge->res2, 0, val);
  454                 }
  455                 handled = 1;
  456         }
  457 
  458         /* Schedule SWI for real handling. */
  459         if (handled)
  460                 swi_sched(nges->swi_ih, SWI_FROMNMI);
  461 
  462         return (handled);
  463 }
  464 
  465 static void
  466 apei_callout_handler(void *context)
  467 {
  468         struct apei_pges *pges = context;
  469         struct apei_ge *ge;
  470 
  471         TAILQ_FOREACH(ge, &pges->ges, nlink)
  472                 apei_ge_handler(ge, false);
  473         callout_schedule_sbt(&pges->poll, pges->interval, pges->interval, 0);
  474 }
  475 
  476 static void
  477 apei_notify_handler(ACPI_HANDLE h, UINT32 notify, void *context)
  478 {
  479         device_t dev = context;
  480         struct apei_softc *sc = device_get_softc(dev);
  481         struct apei_ge *ge;
  482 
  483         TAILQ_FOREACH(ge, &sc->iges.ges, nlink)
  484                 apei_ge_handler(ge, false);
  485 }
  486 
  487 static int
  488 hest_parse_structure(struct apei_softc *sc, void *addr, int remaining)
  489 {
  490         ACPI_HEST_HEADER *hdr = addr;
  491         struct apei_ge *ge;
  492 
  493         if (remaining < (int)sizeof(ACPI_HEST_HEADER))
  494                 return (-1);
  495 
  496         switch (hdr->Type) {
  497         case ACPI_HEST_TYPE_IA32_CHECK: {
  498                 ACPI_HEST_IA_MACHINE_CHECK *s = addr;
  499                 return (sizeof(*s) + s->NumHardwareBanks *
  500                     sizeof(ACPI_HEST_IA_ERROR_BANK));
  501         }
  502         case ACPI_HEST_TYPE_IA32_CORRECTED_CHECK: {
  503                 ACPI_HEST_IA_CORRECTED *s = addr;
  504                 return (sizeof(*s) + s->NumHardwareBanks *
  505                     sizeof(ACPI_HEST_IA_ERROR_BANK));
  506         }
  507         case ACPI_HEST_TYPE_IA32_NMI: {
  508                 ACPI_HEST_IA_NMI *s = addr;
  509                 return (sizeof(*s));
  510         }
  511         case ACPI_HEST_TYPE_AER_ROOT_PORT: {
  512                 ACPI_HEST_AER_ROOT *s = addr;
  513                 return (sizeof(*s));
  514         }
  515         case ACPI_HEST_TYPE_AER_ENDPOINT: {
  516                 ACPI_HEST_AER *s = addr;
  517                 return (sizeof(*s));
  518         }
  519         case ACPI_HEST_TYPE_AER_BRIDGE: {
  520                 ACPI_HEST_AER_BRIDGE *s = addr;
  521                 return (sizeof(*s));
  522         }
  523         case ACPI_HEST_TYPE_GENERIC_ERROR: {
  524                 ACPI_HEST_GENERIC *s = addr;
  525                 ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO);
  526                 ge->v1 = *s;
  527                 TAILQ_INSERT_TAIL(&sc->ges, ge, link);
  528                 return (sizeof(*s));
  529         }
  530         case ACPI_HEST_TYPE_GENERIC_ERROR_V2: {
  531                 ACPI_HEST_GENERIC_V2 *s = addr;
  532                 ge = malloc(sizeof(*ge), M_DEVBUF, M_WAITOK | M_ZERO);
  533                 ge->v2 = *s;
  534                 TAILQ_INSERT_TAIL(&sc->ges, ge, link);
  535                 return (sizeof(*s));
  536         }
  537         case ACPI_HEST_TYPE_IA32_DEFERRED_CHECK: {
  538                 ACPI_HEST_IA_DEFERRED_CHECK *s = addr;
  539                 return (sizeof(*s) + s->NumHardwareBanks *
  540                     sizeof(ACPI_HEST_IA_ERROR_BANK));
  541         }
  542         default:
  543                 return (-1);
  544         }
  545 }
  546 
  547 static void
  548 hest_parse_table(struct apei_softc *sc)
  549 {
  550         ACPI_TABLE_HEST *hest = sc->hest;
  551         char *cp;
  552         int remaining, consumed;
  553 
  554         remaining = hest->Header.Length - sizeof(ACPI_TABLE_HEST);
  555         while (remaining > 0) {
  556                 cp = (char *)hest + hest->Header.Length - remaining;
  557                 consumed = hest_parse_structure(sc, cp, remaining);
  558                 if (consumed <= 0)
  559                         break;
  560                 else
  561                         remaining -= consumed;
  562         }
  563 }
  564 
  565 static char *apei_ids[] = { "PNP0C33", NULL };
  566 static devclass_t apei_devclass;
  567 
  568 static ACPI_STATUS
  569 apei_find(ACPI_HANDLE handle, UINT32 level, void *context,
  570     void **status)
  571 {
  572         int *found = (int *)status;
  573         char **ids;
  574 
  575         for (ids = apei_ids; *ids != NULL; ids++) {
  576                 if (acpi_MatchHid(handle, *ids)) {
  577                         *found = 1;
  578                         break;
  579                 }
  580         }
  581         return (AE_OK);
  582 }
  583 
  584 static void
  585 apei_identify(driver_t *driver, device_t parent)
  586 {
  587         device_t        child;
  588         int             found;
  589         ACPI_TABLE_HEADER *hest;
  590         ACPI_STATUS     status;
  591 
  592         if (acpi_disabled("apei"))
  593                 return;
  594 
  595         /* Without HEST table we have nothing to do. */
  596         status = AcpiGetTable(ACPI_SIG_HEST, 0, &hest);
  597         if (ACPI_FAILURE(status))
  598                 return;
  599         AcpiPutTable(hest);
  600 
  601         /* Only one APEI device can exist. */
  602         if (devclass_get_device(apei_devclass, 0))
  603                 return;
  604 
  605         /* Search for ACPI error device to be used. */
  606         found = 0;
  607         AcpiWalkNamespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT,
  608             100, apei_find, NULL, NULL, (void *)&found);
  609         if (found)
  610                 return;
  611 
  612         /* If not found - create a fake one. */
  613         child = BUS_ADD_CHILD(parent, 2, "apei", 0);
  614         if (child == NULL)
  615                 printf("%s: can't add child\n", __func__);
  616 }
  617 
  618 static int
  619 apei_probe(device_t dev)
  620 {
  621         ACPI_TABLE_HEADER *hest;
  622         ACPI_STATUS     status;
  623         int rv;
  624 
  625         if (acpi_disabled("apei"))
  626                 return (ENXIO);
  627 
  628         if (acpi_get_handle(dev) != NULL) {
  629                 rv = (ACPI_ID_PROBE(device_get_parent(dev), dev, apei_ids) == NULL);
  630                 if (rv > 0)
  631                         return (rv);
  632         } else
  633                 rv = 0;
  634 
  635         /* Without HEST table we have nothing to do. */
  636         status = AcpiGetTable(ACPI_SIG_HEST, 0, &hest);
  637         if (ACPI_FAILURE(status))
  638                 return (ENXIO);
  639         AcpiPutTable(hest);
  640 
  641         device_set_desc(dev, "ACPI Platform Error Interface");
  642         return (rv);
  643 }
  644 
  645 static int
  646 apei_attach(device_t dev)
  647 {
  648         struct apei_softc *sc = device_get_softc(dev);
  649         struct apei_pges *pges;
  650         struct apei_ge *ge;
  651         ACPI_STATUS status;
  652         int rid;
  653 
  654         TAILQ_INIT(&sc->ges);
  655         TAILQ_INIT(&sc->nges.ges);
  656         TAILQ_INIT(&sc->iges.ges);
  657         for (int i = 0; i < nitems(sc->pges); i++) {
  658                 pges = &sc->pges[i];
  659                 pges->interval = SBT_1MS << i;
  660                 callout_init(&pges->poll, 1);
  661                 TAILQ_INIT(&pges->ges);
  662         }
  663 
  664         /* Search and parse HEST table. */
  665         status = AcpiGetTable(ACPI_SIG_HEST, 0, (ACPI_TABLE_HEADER **)&sc->hest);
  666         if (ACPI_FAILURE(status))
  667                 return (ENXIO);
  668         hest_parse_table(sc);
  669         AcpiPutTable((ACPI_TABLE_HEADER *)sc->hest);
  670 
  671         rid = 0;
  672         TAILQ_FOREACH(ge, &sc->ges, link) {
  673                 ge->res_rid = rid++;
  674                 acpi_bus_alloc_gas(dev, &ge->res_type, &ge->res_rid,
  675                     &ge->v1.ErrorStatusAddress, &ge->res, 0);
  676                 if (ge->res) {
  677                         ge->buf = pmap_mapdev_attr(READ8(ge->res, 0),
  678                             ge->v1.ErrorBlockLength, VM_MEMATTR_WRITE_COMBINING);
  679                 } else {
  680                         device_printf(dev, "Can't allocate status resource.\n");
  681                 }
  682                 if (ge->v1.Header.Type == ACPI_HEST_TYPE_GENERIC_ERROR_V2) {
  683                         ge->res2_rid = rid++;
  684                         acpi_bus_alloc_gas(dev, &ge->res2_type, &ge->res2_rid,
  685                             &ge->v2.ReadAckRegister, &ge->res2, 0);
  686                         if (ge->res2 == NULL)
  687                                 device_printf(dev, "Can't allocate ack resource.\n");
  688                 }
  689                 if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) {
  690                         pges = &sc->pges[PGE_ID(ge)];
  691                         TAILQ_INSERT_TAIL(&sc->pges[PGE_ID(ge)].ges, ge, nlink);
  692                         callout_reset_sbt(&pges->poll, pges->interval, pges->interval,
  693                             apei_callout_handler, pges, 0);
  694                 } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_SCI ||
  695                     ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GPIO ||
  696                     ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GSIV) {
  697                         TAILQ_INSERT_TAIL(&sc->iges.ges, ge, nlink);
  698                 } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) {
  699                         ge->copybuf = malloc(ge->v1.ErrorBlockLength,
  700                             M_DEVBUF, M_WAITOK | M_ZERO);
  701                         TAILQ_INSERT_TAIL(&sc->nges.ges, ge, nlink);
  702                         if (sc->nges.swi_ih == NULL) {
  703                                 swi_add(&clk_intr_event, "apei", apei_nmi_swi,
  704                                     &sc->nges, SWI_CLOCK, INTR_MPSAFE,
  705                                     &sc->nges.swi_ih);
  706                                 apei_nmi_nges = &sc->nges;
  707                                 apei_nmi = apei_nmi_handler;
  708                         }
  709                 }
  710         }
  711 
  712         if (acpi_get_handle(dev) != NULL) {
  713                 AcpiInstallNotifyHandler(acpi_get_handle(dev),
  714                     ACPI_DEVICE_NOTIFY, apei_notify_handler, dev);
  715         }
  716         return (0);
  717 }
  718 
  719 static int
  720 apei_detach(device_t dev)
  721 {
  722         struct apei_softc *sc = device_get_softc(dev);
  723         struct apei_ge *ge;
  724 
  725         apei_nmi = NULL;
  726         apei_nmi_nges = NULL;
  727         if (sc->nges.swi_ih != NULL) {
  728                 swi_remove(&sc->nges.swi_ih);
  729                 sc->nges.swi_ih = NULL;
  730         }
  731         if (acpi_get_handle(dev) != NULL) {
  732                 AcpiRemoveNotifyHandler(acpi_get_handle(dev),
  733                     ACPI_DEVICE_NOTIFY, apei_notify_handler);
  734         }
  735         for (int i = 0; i < nitems(sc->pges); i++)
  736                 callout_drain(&sc->pges[i].poll);
  737 
  738         while ((ge = TAILQ_FIRST(&sc->ges)) != NULL) {
  739                 TAILQ_REMOVE(&sc->ges, ge, link);
  740                 if (ge->res) {
  741                         bus_release_resource(dev, ge->res_type,
  742                             ge->res_rid, ge->res);
  743                 }
  744                 if (ge->res2) {
  745                         bus_release_resource(dev, ge->res2_type,
  746                             ge->res2_rid, ge->res2);
  747                 }
  748                 if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_POLLED) {
  749                         TAILQ_REMOVE(&sc->pges[PGE_ID(ge)].ges, ge, nlink);
  750                 } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_SCI ||
  751                     ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GPIO ||
  752                     ge->v1.Notify.Type == ACPI_HEST_NOTIFY_GSIV) {
  753                         TAILQ_REMOVE(&sc->iges.ges, ge, nlink);
  754                 } else if (ge->v1.Notify.Type == ACPI_HEST_NOTIFY_NMI) {
  755                         TAILQ_REMOVE(&sc->nges.ges, ge, nlink);
  756                         free(ge->copybuf, M_DEVBUF);
  757                 }
  758                 if (ge->buf) {
  759                         pmap_unmapdev((vm_offset_t)ge->buf,
  760                             ge->v1.ErrorBlockLength);
  761                 }
  762                 free(ge, M_DEVBUF);
  763         }
  764         return (0);
  765 }
  766 
  767 static device_method_t apei_methods[] = {
  768         /* Device interface */
  769         DEVMETHOD(device_identify, apei_identify),
  770         DEVMETHOD(device_probe, apei_probe),
  771         DEVMETHOD(device_attach, apei_attach),
  772         DEVMETHOD(device_detach, apei_detach),
  773         DEVMETHOD_END
  774 };
  775 
  776 static driver_t apei_driver = {
  777         "apei",
  778         apei_methods,
  779         sizeof(struct apei_softc),
  780 };
  781 
  782 DRIVER_MODULE(apei, acpi, apei_driver, apei_devclass, 0, 0);
  783 MODULE_DEPEND(apei, acpi, 1, 1, 1);

Cache object: 3517080482b8407e4c21a7c45743e262


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