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((vm_offset_t)ge->buf, 791 ge->v1.ErrorBlockLength); 792 } 793 free(ge, M_DEVBUF); 794 } 795 return (0); 796 } 797 798 static device_method_t apei_methods[] = { 799 /* Device interface */ 800 DEVMETHOD(device_identify, apei_identify), 801 DEVMETHOD(device_probe, apei_probe), 802 DEVMETHOD(device_attach, apei_attach), 803 DEVMETHOD(device_detach, apei_detach), 804 DEVMETHOD_END 805 }; 806 807 static driver_t apei_driver = { 808 "apei", 809 apei_methods, 810 sizeof(struct apei_softc), 811 }; 812 813 static int 814 apei_modevent(struct module *mod __unused, int evt, void *cookie __unused) 815 { 816 int err = 0; 817 818 switch (evt) { 819 case MOD_LOAD: 820 sysctl_ctx_init(&apei_sysctl_ctx); 821 break; 822 case MOD_UNLOAD: 823 sysctl_ctx_free(&apei_sysctl_ctx); 824 break; 825 default: 826 err = EINVAL; 827 } 828 return (err); 829 } 830 831 DRIVER_MODULE(apei, acpi, apei_driver, apei_modevent, 0); 832 MODULE_DEPEND(apei, acpi, 1, 1, 1); 833