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

Cache object: a9c549292e5d8a5b202c1ea15c2d3d15


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