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