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); 784